docker-compose.yaml:
version: '3.3' services: nginx: image: nginx:latest ports: - 8080:80
With regards to the preceding docker-compose file, we have the term services that refers to all the applications that we would be running in one go. In this first example test, we can attempt to run the nginx container image under the service called nginx.
We can also set it such that we would export port 80 of the nginx container to our current workstation’s port 8080.
zzh@ZZHPC:/zdata/MyPrograms/Go/aaa$ docker compose -f docker-compose.yaml up [+] Running 2/1 ✔ Network aaa_default Created 0.1s ✔ Container aaa-nginx-1 Created 0.0s Attaching to aaa-nginx-1 aaa-nginx-1 | /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration aaa-nginx-1 | /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/ aaa-nginx-1 | /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh aaa-nginx-1 | 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf aaa-nginx-1 | 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf aaa-nginx-1 | /docker-entrypoint.sh: Sourcing /docker-entrypoint.d/15-local-resolvers.envsh aaa-nginx-1 | /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh aaa-nginx-1 | /docker-entrypoint.sh: Launching /docker-entrypoint.d/30-tune-worker-processes.sh aaa-nginx-1 | /docker-entrypoint.sh: Configuration complete; ready for start up aaa-nginx-1 | 2023/09/25 03:15:50 [notice] 1#1: using the "epoll" event method aaa-nginx-1 | 2023/09/25 03:15:50 [notice] 1#1: nginx/1.25.2 aaa-nginx-1 | 2023/09/25 03:15:50 [notice] 1#1: built by gcc 12.2.0 (Debian 12.2.0-14) aaa-nginx-1 | 2023/09/25 03:15:50 [notice] 1#1: OS: Linux 6.2.0-33-generic aaa-nginx-1 | 2023/09/25 03:15:50 [notice] 1#1: getrlimit(RLIMIT_NOFILE): 1048576:1048576 aaa-nginx-1 | 2023/09/25 03:15:50 [notice] 1#1: start worker processes aaa-nginx-1 | 2023/09/25 03:15:50 [notice] 1#1: start worker process 29 aaa-nginx-1 | 2023/09/25 03:15:50 [notice] 1#1: start worker process 30 aaa-nginx-1 | 2023/09/25 03:15:50 [notice] 1#1: start worker process 31 aaa-nginx-1 | 2023/09/25 03:15:50 [notice] 1#1: start worker process 32 aaa-nginx-1 | 2023/09/25 03:15:50 [notice] 1#1: start worker process 33 aaa-nginx-1 | 2023/09/25 03:15:50 [notice] 1#1: start worker process 34 ^CGracefully stopping... (press Ctrl+C again to force) Aborting on container exit... [+] Stopping 1/1 ✔ Container aaa-nginx-1 Stopped 0.4s canceled
We can stop running the nginx application via docker-compose by doing a keyboard interrupt. However, the application would still be around (although stopped), and we will probably be unable to rerun the command: docker-compose -f docker-compose.yaml up once more without any issue. To properly clean up, we can run the following command:
zzh@ZZHPC:/zdata/MyPrograms/Go/aaa$ docker compose -f docker-compose.yaml down [+] Running 2/2 ✔ Container aaa-nginx-1 Removed 0.0s ✔ Network aaa_default Removed
docker-compose.yaml:
version: '3.3'
services:
app:
build:
context: .
dockerfile: dockerfile
ports:
- 8080:8080
When we use build here, it serves as some sort of indication to docker-compose that the image for this service might require us to run a Docker container build process to generate it.
zzh@ZZHPC:/zdata/MyPrograms/Go/aaa$ docker compose -f docker-compose.yaml up -d [+] Building 9.2s (12/12) FINISHED docker:default => [app internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [app internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 214B 0.0s => [app internal] load metadata for docker.io/library/golang:1.21 2.8s => [app 1/7] FROM docker.io/library/golang:1.21@sha256:c416ceeec1cdf037b80baef1ccb402c230ab83a9134b34c0902c542eb4539c82 0.0s => [app internal] load build context 0.0s => => transferring context: 459B 0.0s => CACHED [app 2/7] WORKDIR /app 0.0s => CACHED [app 3/7] ADD go.mod go.sum ./ 0.0s => CACHED [app 4/7] RUN go env -w GOPROXY=https://goproxy.io,direct 0.0s => CACHED [app 5/7] RUN go mod download 0.0s => [app 6/7] ADD . . 0.0s => [app 7/7] RUN go build -o app . 6.1s => [app] exporting to image 0.3s => => exporting layers 0.3s => => writing image sha256:c5ca78c1b68074e5e4031f248a133252105b44ba94a62d45497a9a7fe7348b1d 0.0s => => naming to docker.io/library/aaa-app 0.0s [+] Running 2/2 ✔ Network aaa_default Created 0.1s ✔ Container aaa-app-1 Started
zzh@ZZHPC:/zdata/MyPrograms/Go/aaa$ docker compose logs aaa-app-1 | 2023/09/25 03:28:10 Hello world sample started.
docker-compose.yaml:
version: '3.3' services: nginx: image: nginx:latest ports: - 8081:80 app: build: context: . dockerfile: Dockerfile ports: - 8080:8080
zzh@ZZHPC:/zdata/MyPrograms/Go/aaa$ docker compose -f docker-compose.yaml up -d [+] Running 2/2 ✔ Container aaa-nginx-1 Started 0.0s ✔ Container aaa-app-1 Running
zzh@ZZHPC:/zdata/MyPrograms/Go/aaa$ docker compose -f docker-compose.yaml down [+] Running 3/3 ✔ Container aaa-app-1 Removed 0.2s ✔ Container aaa-nginx-1 Removed 0.4s ✔ Network aaa_default Removed
docker-compose.yaml:
version: '3.7' services: looper: build: ./serviceB restart: always depends_on: - web - db environment: - SERVICE_A_URL=http://web:8080/revenue web: build: ./serviceA command: > sh -c "/app migrate && /app server" ports: - 8080:8080 restart: always depends_on: - db environment: - DB_HOST=db db: image: mysql:5.7 ports: - 3306:3306 environment: - MYSQL_USER=user - MYSQL_PASSWORD=password - MYSQL_DATABASE=application - MYSQL_ROOT_PASSWORD=my-secret-pw
Dockerfile under SERVICEA:
FROM golang:1.21 as source WORKDIR /app ADD go.mod go.sum ./ RUN go env -w GOPROXY=https://goproxy.io,direct RUN go mod download ADD . . RUN go build -o app . FROM debian COPY --from=source /app/app /app CMD ["/app"]
Dockerfile under SERVICEB:
FROM golang:1.21 as source WORKDIR /app ADD go.mod . RUN go env -w GOPROXY=https://goproxy.io,direct RUN go mod download ADD . . RUN go build -o app . FROM debian COPY --from=source /app/app /app CMD [ "/app" ]
zzh@ZZHPC:/zdata/MyPrograms/Go$ docker compose up --build [+] Running 12/1 ✔ db 11 layers [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿] 0B/0B Pulled 295.5s [+] Building 0.0s (0/0) docker:default unable to prepare context: path "/zdata/MyPrograms/Go/serviceA" not found
After changing the two build paths in docker-compose.yaml, the command can succeed:
version: '3.7' services: looper: build: ./SERVICEB restart: always depends_on: - web - db environment: - SERVICE_A_URL=http://web:8080/revenue web: build: ./SERVICEA command: > sh -c "/app migrate && /app server" ports: - 8080:8080 restart: always depends_on: - db environment: - DB_HOST=db db: image: mysql:5.7 ports: - 3306:3306 environment: - MYSQL_USER=user - MYSQL_PASSWORD=password - MYSQL_DATABASE=application - MYSQL_ROOT_PASSWORD=my-secret-pw
zzh@ZZHPC:/zdata/MyPrograms/Go$ docker compose down [+] Running 4/4 ✔ Container go-looper-1 Removed 0.0s ✔ Container go-web-1 Removed 0.0s ✔ Container go-db-1 Removed 0.0s ✔ Network go_default Removed
zzh@ZZHPC:/zdata/MyPrograms/Go$ docker compose up --build -d [+] Building 2.6s (25/25) FINISHED docker:default => [web internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 256B 0.0s => [web internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [looper internal] load metadata for docker.io/library/debian:latest 2.5s => [looper internal] load metadata for docker.io/library/golang:1.21 2.5s => [looper source 1/7] FROM docker.io/library/golang:1.21@sha256:c416ceeec1cdf037b80baef1ccb402c230ab83a9134b34c0902c542eb4539c82 0.0s => [looper stage-1 1/2] FROM docker.io/library/debian@sha256:eaace54a93d7b69c7c52bb8ddf9b3fcba0c106a497bc1fdbb89a6299cf945c63 0.0s => [web internal] load build context 0.0s => => transferring context: 263B 0.0s => CACHED [looper source 2/7] WORKDIR /app 0.0s => CACHED [web source 3/7] ADD go.mod go.sum ./ 0.0s => CACHED [web source 4/7] RUN go env -w GOPROXY=https://goproxy.io,direct 0.0s => CACHED [web source 5/7] RUN go mod download 0.0s => CACHED [web source 6/7] ADD . . 0.0s => CACHED [web source 7/7] RUN go build -o app . 0.0s => CACHED [web stage-1 2/2] COPY --from=source /app/app /app 0.0s => [web] exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:4057e67d30519f74fc833eddedf6357b7a0313b4a2a7f1967beb95715371c206 0.0s => => naming to docker.io/library/go-web 0.0s => [looper internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [looper internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 250B 0.0s => [looper internal] load build context 0.0s => => transferring context: 84B 0.0s => CACHED [looper source 3/7] ADD go.mod . 0.0s => CACHED [looper source 4/7] RUN go env -w GOPROXY=https://goproxy.io,direct 0.0s => CACHED [looper source 5/7] RUN go mod download 0.0s => CACHED [looper source 6/7] ADD . . 0.0s => CACHED [looper source 7/7] RUN go build -o app . 0.0s => CACHED [looper stage-1 2/2] COPY --from=source /app/app /app 0.0s => [looper] exporting to image 0.0s => => exporting layers 0.0s => => writing image sha256:01d32c40f95441f1e8051f3a42ba2705b4a8b1dc3af86e61fae22125a9a04540 0.0s => => naming to docker.io/library/go-looper 0.0s [+] Running 4/4 ✔ Network go_default Created 0.1s ✔ Container go-db-1 Started 0.0s ✔ Container go-web-1 Started 0.0s ✔ Container go-looper-1 Started
zzh@ZZHPC:/zdata/MyPrograms/Go$ docker container inspect go-web-1 [ { "Id": "58732dbfa34f352ad19f17c4a28617e130ce807add597c262fb0df0f4612f040", "Created": "2023-09-26T02:21:11.451551323Z", "Path": "sh", "Args": [ "-c", "/app migrate &&\n /app server" ], "State": { "Status": "running", "Running": true, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": false, "Pid": 24319, "ExitCode": 0, "Error": "", "StartedAt": "2023-09-26T02:21:20.498310705Z", "FinishedAt": "2023-09-26T02:21:17.256456663Z" }, "Image": "sha256:4057e67d30519f74fc833eddedf6357b7a0313b4a2a7f1967beb95715371c206", "ResolvConfPath": "/var/lib/docker/containers/58732dbfa34f352ad19f17c4a28617e130ce807add597c262fb0df0f4612f040/resolv.conf", "HostnamePath": "/var/lib/docker/containers/58732dbfa34f352ad19f17c4a28617e130ce807add597c262fb0df0f4612f040/hostname", "HostsPath": "/var/lib/docker/containers/58732dbfa34f352ad19f17c4a28617e130ce807add597c262fb0df0f4612f040/hosts", "LogPath": "/var/lib/docker/containers/58732dbfa34f352ad19f17c4a28617e130ce807add597c262fb0df0f4612f040/58732dbfa34f352ad19f17c4a28617e130ce807add597c262fb0df0f4612f040-json.log", "Name": "/go-web-1", "RestartCount": 6, "Driver": "overlay2", "Platform": "linux", "MountLabel": "", "ProcessLabel": "", "AppArmorProfile": "docker-default", "ExecIDs": null, "HostConfig": { "Binds": null, "ContainerIDFile": "", "LogConfig": { "Type": "json-file", "Config": {} }, "NetworkMode": "go_default", "PortBindings": { "8080/tcp": [ { "HostIp": "", "HostPort": "8080" } ] }, "RestartPolicy": { "Name": "always", "MaximumRetryCount": 0 }, "AutoRemove": false, "VolumeDriver": "", "VolumesFrom": null, "ConsoleSize": [ 0, 0 ], "CapAdd": null, "CapDrop": null, "CgroupnsMode": "private", "Dns": null, "DnsOptions": null, "DnsSearch": null, "ExtraHosts": [], "GroupAdd": null, "IpcMode": "private", "Cgroup": "", "Links": null, "OomScoreAdj": 0, "PidMode": "", "Privileged": false, "PublishAllPorts": false, "ReadonlyRootfs": false, "SecurityOpt": null, "UTSMode": "", "UsernsMode": "", "ShmSize": 67108864, "Runtime": "runc", "Isolation": "", "CpuShares": 0, "Memory": 0, "NanoCpus": 0, "CgroupParent": "", "BlkioWeight": 0, "BlkioWeightDevice": null, "BlkioDeviceReadBps": null, "BlkioDeviceWriteBps": null, "BlkioDeviceReadIOps": null, "BlkioDeviceWriteIOps": null, "CpuPeriod": 0, "CpuQuota": 0, "CpuRealtimePeriod": 0, "CpuRealtimeRuntime": 0, "CpusetCpus": "", "CpusetMems": "", "Devices": null, "DeviceCgroupRules": null, "DeviceRequests": null, "MemoryReservation": 0, "MemorySwap": 0, "MemorySwappiness": null, "OomKillDisable": null, "PidsLimit": null, "Ulimits": null, "CpuCount": 0, "CpuPercent": 0, "IOMaximumIOps": 0, "IOMaximumBandwidth": 0, "MaskedPaths": [ "/proc/asound", "/proc/acpi", "/proc/kcore", "/proc/keys", "/proc/latency_stats", "/proc/timer_list", "/proc/timer_stats", "/proc/sched_debug", "/proc/scsi", "/sys/firmware" ], "ReadonlyPaths": [ "/proc/bus", "/proc/fs", "/proc/irq", "/proc/sys", "/proc/sysrq-trigger" ] }, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/0f6e196d4bfac07e0770e1408ec121e6d0444ad0d1d6986c30de378a3f340e08-init/diff:/var/lib/docker/overlay2/n28gwo11o2q9ewkxcb7w4vnl4/diff:/var/lib/docker/overlay2/fa328e3060613cb46dd48605c44cbfd2da1a0b527a07997545649d50019017c8/diff", "MergedDir": "/var/lib/docker/overlay2/0f6e196d4bfac07e0770e1408ec121e6d0444ad0d1d6986c30de378a3f340e08/merged", "UpperDir": "/var/lib/docker/overlay2/0f6e196d4bfac07e0770e1408ec121e6d0444ad0d1d6986c30de378a3f340e08/diff", "WorkDir": "/var/lib/docker/overlay2/0f6e196d4bfac07e0770e1408ec121e6d0444ad0d1d6986c30de378a3f340e08/work" }, "Name": "overlay2" }, "Mounts": [], "Config": { "Hostname": "58732dbfa34f", "Domainname": "", "User": "", "AttachStdin": false, "AttachStdout": true, "AttachStderr": true, "ExposedPorts": { "8080/tcp": {} }, "Tty": false, "OpenStdin": false, "StdinOnce": false, "Env": [ "DB_HOST=db", "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "sh", "-c", "/app migrate &&\n /app server" ], "Image": "go-web", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": { "com.docker.compose.config-hash": "baa13c3dbdfc2c2a0dc74631d3aeb525a5ed5b1fca180ee36e69ceeafaa768ea", "com.docker.compose.container-number": "1", "com.docker.compose.depends_on": "db:service_started:false", "com.docker.compose.image": "sha256:4057e67d30519f74fc833eddedf6357b7a0313b4a2a7f1967beb95715371c206", "com.docker.compose.oneoff": "False", "com.docker.compose.project": "go", "com.docker.compose.project.config_files": "/zdata/MyPrograms/Go/docker-compose.yaml", "com.docker.compose.project.working_dir": "/zdata/MyPrograms/Go", "com.docker.compose.service": "web", "com.docker.compose.version": "2.21.0" } }, "NetworkSettings": { "Bridge": "", "SandboxID": "31c9ef4ddb84f6e06be7f4a592b49c299e58c218545c9c0ed763e4aa34a146ad", "HairpinMode": false, "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "Ports": { "8080/tcp": [ { "HostIp": "0.0.0.0", "HostPort": "8080" }, { "HostIp": "::", "HostPort": "8080" } ] }, "SandboxKey": "/var/run/docker/netns/31c9ef4ddb84", "SecondaryIPAddresses": null, "SecondaryIPv6Addresses": null, "EndpointID": "", "Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "IPAddress": "", "IPPrefixLen": 0, "IPv6Gateway": "", "MacAddress": "", "Networks": { "go_default": { "IPAMConfig": null, "Links": null, "Aliases": [ "go-web-1", "web", "58732dbfa34f" ], "NetworkID": "0f68c8be7cc2c50dfbc22a3c5cce040a33f72ba203bbcde1cb7e151706b76e4d", "EndpointID": "461bebf91f93c118082152e1164cd4fe035f883b2089d0638a82a2226f5d8b74", "Gateway": "172.19.0.1", "IPAddress": "172.19.0.4", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:13:00:04", "DriverOpts": null } } } } ]
Observe that we have the web word there, which is a network alias that can be used to reference to this container in the compose stack. The other alias, which is hash, can also be used. But it is definitely not as simple and memorable as using the names defined in the docker-compose.yaml file.