Skip to Main Content

Goss: Service Validation and Docker Integration

In this guide, we will explore in detail what Goss is, how it is used to validate and maintain the health of services, and how you can easily integrate it into your Docker images. For those looking to improve the quality of their development and deployments, Goss presents itself as a reliable and efficient solution.

What is Goss?

Goss is an infrastructure service validation tool that can be used to verify that a Docker service is working correctly. You can use Goss to create and run integration tests on your Docker service, allowing you to ensure that it is configured correctly and is responding as expected. Goss is easy to use and integrates well with Docker, making it an excellent choice for validating Docker services.

Uses of the Goss tool

Goss can be used in Linux to validate a variety of aspects of service configuration and behaviour. Some examples of uses of Goss in Linux include:

  • Validation of network configurations: Goss can be used to verify that network services, such as DNS and DHCP, are configured correctly and responding to requests.
  • Validation of security settings: Goss can be used to verify that security settings, such as firewall and SSH access, are configured correctly.
  • Validation of system configurations: Goss can be used to verify that system services, such as memory and disk space settings, are configured correctly.
  • Validation of application services: Goss can be used to verify that application services, such as a web server or database, are functioning correctly and responding to requests.
  • Validation of monitoring configurations: Goss can be used to verify that monitoring services, such as Zabbix or Nagios, are configured correctly and collecting the correct data.

It is important to note that these are just some of the possible uses of Goss in Linux, as its flexibility allows it to adapt to a wide variety of environments and situations.

Installation and service validation: How to validate with Goss

Let’s see an example of how to validate with Goss, following the general steps below:

  1. Install Goss: To make use of Goss, you will first need to install it on your Linux system. You can do this by downloading the binary package from the Goss download page or by using a package manager such as apt or yum.
  2. Create the tests: Goss uses a YAML scripting language to specify the tests to be performed. Create a YAML file with the tests you want to run on your service.
  3. Run the tests: use the goss run command to run the tests specified in the YAML file.
  4. Review results: Goss presents test results in a standardized format. If any test fails, the error will be reported, and the problem detailed.

Example:

# Install Goss
curl -fsSL https://goss.rocks/install | sh

# Create a test file to verify that the web service is working correctly.
echo "http:
  # Verify that the server is responding
  status: 200
  # Verify that the server is responding with the expected content
  body: /Welcome to my website/" > test.yaml

# Execute the tests
goss --gossfile test.yaml validate

In this example, the web service is verified to be working correctly by responding with a status code 200 and a specific content. If the test fails, the error will be reported.

How to configure Goss in a docker image

It is possible to use Goss to validate services inside a Docker container by adding the necessary instructions to run it in the Dockerfile. By doing so, it will automatically run every time the container is built or started.

Changes to our compose

The first thing we are going to do is to change the way our docker-compose reads the docker image.

This is the normal way to add images to a service in docker, where they are downloaded from the official docker repositories.

version: "3"
services:
  odoo14:
    image: odoo:14.0
    ...

  nginx:
    image: nginx
    ...

  postgres-odoo:
    image: postgres:12.8
    ...

We will change it to create our own image and for this we are going to create a Dockerfile for each service where we are going to have goss.

vagrant@master:~/odoo$ cat dockerfile/odoo14/Dockerfile 
FROM odoo:14.0


vagrant@master:~/odoo$ cat dockerfile/postgres-odoo/Dockerfile 
FROM postgres:12.8


vagrant@master:~/odoo$ cat dockerfile/nginx/Dockerfile 
FROM nginx


With these changes we build the image using the previously created Dockerfile, with this we get to add more parameters or improvements.
We raise the docker-compose and we already have the containers.
vagrant@master:~/odoo$ docker-compose ps
     Name Command State Ports     
--------------------------------------------------------------------------------------------------------------------------------
nginx /docker-entrypoint.sh ngin ...   Up 0.0.0.0.0:443->443/tcp,:::443->443/tcp, 0.0.0.0.0:80->80/tcp,:::80->80/tcp
odoo14 /entrypoint.sh odoo Up 0.0.0.0.0:8069->8069/tcp,:::8069->8069/tcp, 8071/tcp, 8072/tcp        
portainer-odoo /portainer Up 9000/tcp        
postgres-odoo docker-entrypoint.sh postgres Up 0.0.0.0.0:5432->5432/tcp,:::5432->5432/tcp  

In the status column we see that it is Up but we do not know if it’s Healthy or not, for this we are going to configure goss.

We add goss

To validate services, specific test files must be created for each service to be validated. These files should specify the expected parameters and behaviors of the service, and Goss will compare these parameters with the actual values of the service to determine if the service is functioning correctly.

How are we going to configure it?

  • Nginx will check if it has its own port open and also that all services are active, otherwise it will not start the service.
  • Odoo checks if it has its own port active and if it answers the call to the web, then it will check that it has connection to postgres and that it can access the database.
  • Postgres will check only if it has its own port open.

The checks to itself we can put them on the file, goss.yaml. While the checks to other services will be added to the file goss-command.yaml (This name is indicative and can be changed).

Odoo Goss Files

This file verifies that it is listening on port 8069 and will make a call to itself that has to respond with a status code 200 for proper operation.

$ cat dockerfile/odoo/goss/goss.yaml

port:
  tcp:8069:
    listening: true

http:
  http://localhost:8069/web/database/selector:
    status: 200
    allow-insecure: false
    no-follow-redirects: false
    timeout: 5000
    body: []

For the goss-command.yaml file, we are going to perform tests to check the operation of postgres. First, if it responds to the service and then if it can log into the database, for this option we have to have the client of the manager installed on the machine.

$ cat dockerfile/odoo/goss/goss-command.yaml

addr:
  tcp://postgres-odoo:5432:
    reachable: true
    timeout: 500

command:
  PGPASSWORD=$${MY_PASSWORD} psql -h postgres-odoo -U ${MY_USER} -d postgres:
    title: Ensure we have valid credentials
    exit-status: 0
    timeout: 50000 # 5s

Postgres goss files

Postgres will only check if port 5432 is open.

$ cat dockerfile/postgres/goss/goss.yaml

port:
  tcp:5432:
    listening: true

nginx goss files

The first check that nginx will do is to verify if you have port 443 open.

$ cat dockerfile/nginx/goss/goss.yaml

port:
  tcp:443:
    listening: true

We will use nginx as the main service to check all the other services, it will be the last one to fully wake up as it has to wait until the other services have done their checks.

We will add the checks to the services and if any service does not work we can verify its operation in another way, for example, the portainer service we have made a call to the web and if it returns a code 200 it means that it has been able to get up correctly.

$ cat dockerfile/nginx/goss/goss-command.yaml 

addr:
  tcp://postgres-odoo:5432:
    reachable: true
    timeout: 500
  tcp://odoo14:8069:
    reachable: true
    timeout: 500

http:
  http://portainer-odoo:9000:
    status: 200
    allow-insecure: false
    no-follow-redirects: false
    timeout: 5000
    body: []

Add goss to the dockerfile

To use Goss from a Dockerfile, you must first add the instruction to install on the system. This can be done using the install command provided by the project or by using a previously built container image with Goss already installed.

Once Goss is installed, instructions can be added to copy the Goss test files to the container and run Goss. For example, you can add a COPY statement to copy the test files from the host file system to the container, and then a CMD or ENTRYPOINT statement to execute and run the tests.

Let’s configure the Dockerfiles of our infrastructure.

Odoo Dockerfile

FROM odoo:14.0

USER root

RUN apt-get update
RUN apt-get install curl -y

ENV GOSS_VERSION v0.3.11
RUN curl -L https://github.com/aelsabbahy/goss/releases/download/$GOSS_VERSION/goss-linux-amd64 -o /usr/local/bin/goss && \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \
    chmod +rx /usr/local/bin/goss &&&.
    goss --version

COPY goss/ /goss

USER odoo

CMD goss -g /goss/goss/goss-command.yaml validate -r 5m && exec odoo

HEALTHCHECK --interval=1s --timeout=6s CMD goss -g /goss/goss.yaml validate

This example uses an Odoo 14 base image, install it, copy the directory, which will have the two previously created files, to the container and run it to validate the web service.

We perform two checks first we run the goss-command.yaml file and after its verification Odoo starts. Then, it performs a Healthcheck every second with the verification of the goss.yaml file.

Dockerfile of postgres

FROM postgres:12.8

USER root

RUN apt update

RUN apt install curl -y

ENV GOSS_VERSION v0.3.11
RUN curl -L https://github.com/aelsabbahy/goss/releases/download/$GOSS_VERSION/goss-linux-amd64 -o /usr/local/bin/goss && \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \
    chmod +rx /usr/local/bin/goss &&&.
    goss --version

COPY goss/ /goss

HEALTHCHECK --interval=1s --timeout=6s CMD goss -g /goss/goss.yaml validate

Similar example, but with the postgres base image but with its respective checks.

It is important to mention that when running the tests from within a container, the tests will be validating the configuration and behavior of the service within the context of the container, rather than on the host.

Status of services

A Docker container can have three different health states: “healthy”, “unhealthy” or “health: starting”.

  • “Healthy” means that the container is running correctly and meeting all specified health conditions.
  • “Unhealthy” means that the container is not meeting one of the specified health conditions. This may be due to a problem with the service running inside the container or a problem with the container itself.
  • “Health: starting” means that the container is starting and its health status has not yet been determined. This may be because the service has not yet finished starting or because the health tests have not yet been run.

We install the services

Once the instructions have been added, the command “docker-compose up -d” can be used to start the containers and run the Goss tests automatically.

You can use the “docker-compose ps” command to see the status of the containers in your compose file. If a container is “healthy”, it will be shown next to “Up”. If a container is failing it will be shown as “unhealthy”.

$ docker-compose ps
     Name Command State Ports     
---------------------------------------------------------------------------------------------------------------------------------------
metabase /app/run_metabase.sh /bin/ ...   Up (healthy) 3000/tcp        
netdata time bash starter.sh Up (healthy) 0.0.0.0.0:19999->19999/tcp,:::19999->19999/tcp                          
nginx-odoo /docker-entrypoint.sh /bin ...   Up (healthy) 0.0.0.0.0:443->443/tcp,:::443->443/tcp, 0.0.0.0.0:80->80/tcp,:::80->80/tcp
odoo14 /entrypoint.sh /bin/bash - ...   Up (healthy) 0.0.0.0.0:8069->8069/tcp,:::8069->8069/tcp, 8071/tcp, 8072/tcp        
portainer-odoo /portainer --admin-passwor ...   Up 9000/tcp        
postgres-odoo docker-entrypoint.sh postgres Up (healthy) 0.0.0.0:5432->5432/tcp,:::5432->5432/tcp   

What happens if a service goes down?

We are going to stop the database service by simulating that the database is down or could not be installed for some reason.

To stop a specific service in a compose file, you can use the command “docker-compose stop [service name]“.

$ docker-compose stop postgres-odoo
Stopping postgres-odoo ... done

Once you have stopped the service, you can check the status again with docker-compose ps, where we can see that the services we have checking postgres are unhealthy or trying to start.

devops@chakray:~/gitlab-chakray/chdo/chdo/chdo-odoo-platform/odoo14-compose$ docker-compose ps
     Name Command State Ports     
------------------------------------------------------------------------------------------------------------------------------------------------
metabase /app/run_metabase.sh /bin/ ...   Up (healthy) 3000/tcp        
netdata time bash starter.sh Up (health: starting) 0.0.0.0.0:19999->19999/tcp,:::19999->19999/tcp                          
nginx-odoo /docker-entrypoint.sh /bin ...   Up (unhealthy) 0.0.0.0.0:443->443/tcp,::::443->443/tcp, 0.0.0.0.0:80->80/tcp,::::80->80/tcp
odoo14 /entrypoint.sh /bin/bash - ...   Up (health: starting) 0.0.0.0.0:8069->8069/tcp,:::8069->8069/tcp, 8071/tcp, 8072/tcp        
portainer-odoo /portainer --admin-passwor ...   Up 9000/tcp        
postgres-odoo docker-entrypoint.sh postgres Exit 0 

If you want to check the health status of the containers in real time, you can use the command “docker-compose logs -f” to view the logs of the containers while they are running.

nginx-odoo | Attempt #177:
nginx-odoo | ...F
nginx-odoo | 
nginx-odoo | Failures/Skipped:
nginx-odoo | 
nginx-odoo | Addr: tcp://postgres-odoo:5432: reachable:
nginx-odoo | Expected
nginx-odoo | <bool>: false
nginx-odoo | to equal
nginx-odoo | <bool>: true
nginx-odoo | 
nginx-odoo | Total Duration: 0.010s
nginx-odoo | Count: 4, Failed: 1, Skipped: 0
nginx-odoo | Retrying in 1s (elapsed/timeout time: 177.516s/5m0s)

“Count” is the total number of tests executed. “Failed” is the number of tests that failed and “Skipped” is the number of tests that were skipped in the execution.

For example, if the result of running is “Count: 4, Failed: 1, Skipped: 0”, it means that 4 tests were run in total, one of them failed and none was skipped.

In case there are any failed tests, it will show you details about which tests failed and why. You can use this information to correct the problems and re-run the failed tests.

Service is up and running again

Once you have fixed the problems that caused the service to go down and we start it again and recheck if the container is in a healthy state.

devops@chakray:~/gitlab-chakray/chdo/chdo/chdo-odoo-platform/odoo14-compose$ docker-compose up -d
netdata is up-to-date
portainer-odoo is up-to-date
Starting postgres-odoo ... done
metabase is up-to-date
odoo14 is up-to-date
nginx-odoo is up-to-date

We see that it has already connected and we have made sure that the result is Count: [x], Failed: 0, Skipped: 0″, indicating that all tests have passed successfully and there are no errors.

nginx-odoo | Attempt #272:
nginx-odoo | ...F
nginx-odoo | 
nginx-odoo | Failures/Skipped:
nginx-odoo | 
nginx-odoo | Addr: tcp://postgres-odoo:5432: reachable:
nginx-odoo | Expected

nginx-odoo | <bool>: false

nginx-odoo | to equal

nginx-odoo | <bool>: true

nginx-odoo |

nginx-odoo | Total Duration: 0.005s

nginx-odoo | Count: 4, Failed: 1, Skipped: 0

nginx-odoo | Retrying in 1s (elapsed/timeout time: 273.438s/5m0s)

nginx-odoo |

nginx-odoo |

nginx-odoo | Attempt #273:

nginx-odoo | ....

nginx-odoo |

nginx-odoo | Total Duration: 0.004s

nginx-odoo | Count: 4, Failed: 0, Skipped: 0

If you still have problems with the container, you can check the container logs again with the command “docker-compose logs [service name]” to get more information about the problem.

Mapping goss

Why map a file?

Mapping a goss.yaml file to a Docker container has several advantages:

  1. Improved flexibility: By mapping a goss.yaml file into a container, you can customize the configuration to suit your specific needs, rather than being limited by the default Dockerfile configuration.
  2. Enables configuration reuse: By mapping a goss.yaml file to a container, you can reuse the same configuration in several different containers or environments, instead of having to create a different configuration for each container or environment.
  3. Makes it easy to update the configuration: By having the configuration outside the container, you can easily update it without having to rebuild the container image.

In summary, mapping a goss.yaml file into a Docker container allows you to have greater control over configuration, improve flexibility, and facilitate development and upgrades.

Mapping a Goss configuration file

You can map a configuration file into a Docker container at image build time or at container run time.

To do this we create a file with the same name in a directory. In this file we add the checks we need.

$ cat configs/odoo14/goss-command.yaml 

addr:
  tcp://postgres-odoo:5432:
    reachable: true
    timeout: 500

command:
  PGPASSWORD=$${MY_PASSWORD} psql -h postgres-odoo -U ${MY_USER} -d postgres:
    title: Ensure we have valid credentials
    exit-status: 0
    timeout: 50000 # 5s

Mapping a goss.yaml file into a Docker container will overwrite any settings specified in the original Dockerfile in the image. This is because the mapped goss.yaml file is linked to the container at runtime, and takes precedence over any settings specified in the Dockerfile.

It is important to note that this only applies to the configuration. If there are any changes to the container that do not relate to Goss, such as a software dependency, file system changes, etc, these will not be affected by the mapped goss file.

Configuration of docker-compose.yml

To map a goss.yaml file into a Docker container when using Docker Compose, you must specify the path to the goss.yaml file on your local file system in the compose file and the path within the container where you want to place the goss.yaml file.

For example, if your goss.yaml file is located in the path “./configs/odoo14/goss-command.yaml” and you want to map it to the container in the path “/goss/goss-command.yaml”, in your compose file you could add the following line in the corresponding service:

volumes:

./configs/odoo14/goss-command.yaml:/goss/goss-command.yaml

Once this is done, running the command “docker-compose up -d” will create a link between the goss.yaml file on your local file system and the container, allowing it to access the configuration specified in that file.

Conclusion

In summary, Goss is a system validation tool that can be used to verify if Docker containers are in a healthy state. It is a very useful tool to automate testing and ensure that containers meet your configuration requirements.

You can use Goss in conjunction with Docker Compose to check the health status of your containers and map a goss.yaml file into a Docker container for greater control over configuration, improved flexibility, and easier development and upgrades.

If you need more information on how to use this tool, we can provide you with resources and assistance to help you implement it in your project effectively. We are ready to provide you with all the help you need to ensure its successful use. If you would like more information, please contact us.