> ## Docker best practices

> Docker Compose configuration best practices for Antithesis, with an example docker-compose file

> Fetch the complete documentation index at: https://antithesis.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

---

Antithesis runs your system in our testing environment using the configurations in your `docker-compose.yaml` file. For an overview of the process, please check out our [setup guide](/docs/getting_started/setup_guide/docker_compose/).

Here are some best practices we suggest you follow to get the most out of your testing.

There's an example `docker-compose.yaml` file below with explanatory comments.

### Dos

##### Set container names for all of your services

> If you don't set one, Antithesis generates a container name that may be of the form `antithesis-<service-name>-<number>`.

##### Use the same name for container and host names

> It's ideal to use the same name for `container_name` and `hostname`. In the report, logging output will be listed under the `hostname` and if no `hostname` is supplied, it'll be inferred, possibly from the `container_name`.

##### Configure service healthchecks

> To set up Docker provided [healthchecks](https://docs.docker.com/reference/compose-file/services/#healthcheck) for your services, add the `healthcheck` attribute, per service, in your `docker-compose.yaml` configuration.
> It's convenient when configuring a system with dependencies -- when one service depends on another service to be healthy before being started itself. It's also useful when trying to emit a `setup_complete` signal.

##### Configure the order of service startup and shutdown

> Configure the [`depends_on`](https://docs.docker.com/reference/compose-file/services/#depends_on) attribute for services that have dependencies on other services.

##### Prevent entrypoint process from being assigned pid 1

> Set [`init: true`](https://docs.docker.com/reference/compose-file/services/#init) in your containers so the entrypoint process is not assigned to pid 1. It's not possible to get a core dump for a process with pid 1.

### Don'ts

##### Don't use [compose build](https://docs.docker.com/reference/compose-file/build/) for any of your services

> Antithesis expects to receive pre-built images before bringing up your system since there's no internet access within our testing environment.

##### Don't change the default logging driver

> If you specify a custom logging driver, Antithesis will generate logs as normal, but *won't* display them in the debugging artifacts we send you.

##### Don't use underscores in `hostname`

> Per the standards for DNS domain names, underscores are not included in the permissible characters. Using underscores in the `hostname` can create issues in hostname resolution.

##### Don't configure an [internal network](https://docs.docker.com/reference/compose-file/networks/#internal)

> If you do specify `internal: true`, your system will not be able to connect to the Antithesis network.

##### Don't set a [pull policy](https://docs.docker.com/reference/compose-file/services/#pull_policy)

> Antithesis pulls all the container images before spinning up your system because there's no internet access inside the testing environment. So, if you set a pull policy for your services that tries to pull images from a registry, it will fail.

### Example docker-compose file

Here's a `docker-compose.yaml` with comments highlighting the above the points:

```yaml
version: '3.8'

services:

  etcd0:
    image: 'docker.io/bitnamilegacy/etcd:3.5'
    # Don't set a pull policy that forces to pull the image from a registry
    # pull_policy: always
    container_name: etcd0 # Set the container name
    hostname: etcd0 # Use the same name for container_name and hostname and don't use _ in the hostname
    environment: 
      ETCD_NAME: "etcd0"
      ETCD_INITIAL_ADVERTISE_PEER_URLS: "http://etcd0:2380"
      ETCD_LISTEN_PEER_URLS: "http://0.0.0.0:2380"
      ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2379"
      ETCD_ADVERTISE_CLIENT_URLS: "http://etcd0.etcd:2379"
      ETCD_INITIAL_CLUSTER_TOKEN: "etcd-cluster-1"
      ETCD_INITIAL_CLUSTER: "etcd0=http://etcd0:2380,etcd1=http://etcd1:2380,etcd2=http://etcd2:2380"
      ETCD_INITIAL_CLUSTER_STATE: "new"
      ALLOW_NONE_AUTHENTICATION: "yes"
    healthcheck: # Configure Docker provided healthchecks for your services
      test: ["CMD", "etcdctl", "endpoint", "health"]
      interval: 5s
      timeout: 5s
      retries: 3
    init: true # Prevent entrypoint pid 1
    # Don't configure an internal network
    # networks: 
    #   - etcd-example

  etcd1:
    image: 'docker.io/bitnamilegacy/etcd:3.5'
    container_name: etcd1 # Set the container name
    hostname: etcd1 # Use the same value for container_name and hostname and don't use _ in the hostname
    environment: 
      ETCD_NAME: "etcd1"
      ETCD_INITIAL_ADVERTISE_PEER_URLS: "http://etcd1:2380"
      ETCD_LISTEN_PEER_URLS: "http://0.0.0.0:2380"
      ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2379"
      ETCD_ADVERTISE_CLIENT_URLS: "http://etcd1.etcd:2379"
      ETCD_INITIAL_CLUSTER_TOKEN: "etcd-cluster-1"
      ETCD_INITIAL_CLUSTER: "etcd0=http://etcd0:2380,etcd1=http://etcd1:2380,etcd2=http://etcd2:2380"
      ETCD_INITIAL_CLUSTER_STATE: "new"
      ALLOW_NONE_AUTHENTICATION: "yes"
    healthcheck:
      test: ["CMD", "etcdctl", "endpoint", "health"]
      interval: 5s
      timeout: 5s
      retries: 3
    init: true # Prevent entrypoint pid 1
    # Don't configure an internal network
    # networks: 
    #   - etcd-example

  etcd2:
    image: 'docker.io/bitnamilegacy/etcd:3.5'
    container_name: etcd2 # Set the container name
    hostname: etcd2 # Use the same value for container_name and hostname and don't use _ in the hostname
    environment: 
      ETCD_NAME: "etcd2"
      ETCD_INITIAL_ADVERTISE_PEER_URLS: "http://etcd2:2380"
      ETCD_LISTEN_PEER_URLS: "http://0.0.0.0:2380"
      ETCD_LISTEN_CLIENT_URLS: "http://0.0.0.0:2379"
      ETCD_ADVERTISE_CLIENT_URLS: "http://etcd2.etcd:2379"
      ETCD_INITIAL_CLUSTER_TOKEN: "etcd-cluster-1"
      ETCD_INITIAL_CLUSTER: "etcd0=http://etcd0:2380,etcd1=http://etcd1:2380,etcd2=http://etcd2:2380"
      ETCD_INITIAL_CLUSTER_STATE: "new"
      ALLOW_NONE_AUTHENTICATION: "yes"
    healthcheck:
      test: ["CMD", "etcdctl", "endpoint", "health"]
      interval: 5s
      timeout: 5s
      retries: 3
    init: true # Prevent entrypoint pid 1
    # Don't configure an internal network
    # networks: 
    #   - etcd-example

  health-checker:
    image: 'etcd-tutorial-health-checker:tutorial'
    container_name: health-checker # Set the container name
    # No hostname set because it will not be connected by any other services and this service will exit after publishing a setup_complete message
    # hostname: health-checker
    depends_on: # Docker will not start health-checker service until etcd0, etcd1, and etcd2 are marked as healthy
      etcd0:
        condition: service_healthy
      etcd1:
        condition: service_healthy
      etcd2:
        condition: service_healthy
    entrypoint: ['/entrypoint.py']
    # Don't configure an internal network
    # networks: 
    #   - etcd-example

  client1:
    image: 'etcd-tutorial-client:tutorial'
    container_name: client1 # Set the container name
    hostname: client1 # Use the same name for container_name and hostname and don't use _ in the hostname
    entrypoint: "sleep infinity"
    init: true # Prevent entrypoint pid 1
    # Don't change the default logging driver as Antithesis relies on it. If you do specify a custom logging driver, Antithesis will generate logs as normal, but not display them in the debugging artifacts we send you.
    # logging: 
    #   driver: "local"
    # Don't configure an internal network
    # networks: 
    #   - etcd-example

  client2:
    image: 'etcd-tutorial-client:tutorial'
    container_name: client2 # Set the container name
    hostname: client2 # Use the same name for container_name and hostname and don't use _ in the hostname
    entrypoint: "sleep infinity"
    init: true # Prevent entrypoint pid 1
    # Don't configure an internal network
    # networks: 
    #   - etcd-example

# Don't configure an internal network. This prevents your system from connecting to the Antithesis network.
# networks: 
#   etcd-example:
#     internal: true
```
