Compare commits

...

16 Commits

Author SHA1 Message Date
da60952fe4 refactor(docs): Explain Docker registry use 2023-12-24 03:31:14 +01:00
d6ea3f1853 fix(docker-compose): For a single-service Compose file prefill our example README.md with docker compose --profile 'build' build ...
... instead of docker compose --profile
'build-service' build since the latter won't exist.
2023-12-24 03:18:11 +01:00
adb7bf6795 fix(docker-compose): When we have only one service in Docker Compose set its Dockerfile context dir to just build-context/ instead of build-context/service since the latter doesn't exist 2023-12-24 02:56:03 +01:00
215db1682d refactor(docker-compose): Set default ulimits even when var is set (but set to just an empty string) 2023-12-24 01:30:49 +01:00
36f2eecba1 refactor(compose): Copy Docker images with copy-docker 2023-10-13 02:26:41 +02:00
1f588e90bc refactor(compose): Double-check that VIP is bound on target host 2023-10-13 02:23:57 +02:00
b534a9bccf common-settings.yml is now .yaml 2023-10-13 02:08:12 +02:00
e5e78a0527 feat(compose): Work with a registry 2023-10-13 02:06:56 +02:00
d98de5aff0 refactor(compose): Mention private registry when copying 2023-10-13 01:15:24 +02:00
ffaf43e56f common-settings.yml is now .yaml 2023-10-13 01:13:24 +02:00
20d303e79a fix(compose): Update Dockerfile ref to env example file 2023-10-09 01:33:34 +02:00
117627889f fix(compose): Fix bash var quoting 2023-10-08 18:35:10 +02:00
ab9b1009cb fix(compose): Fix line breaks with multi-component build=yes 2023-10-08 17:54:17 +02:00
6605fe0866 Merge pull request 'fix(compose): Use modern Compose file name (#12)' (#13) from 12-compose-file-name-changes into master
Reviewed-on: #13
2023-10-08 15:42:58 +00:00
782981c6f8 fix(compose): Use modern Compose file name (#12) 2023-10-08 17:41:59 +02:00
aef611f731 Merge pull request '10-compose-add-conventional-commits' (#11) from 10-compose-add-conventional-commits into master
Reviewed-on: #11
2023-10-08 15:29:43 +00:00
22 changed files with 162 additions and 105 deletions

View File

@@ -56,9 +56,9 @@ The end result is a directory structure that has everything you need to hit the
│   ├── Dockerfile │   ├── Dockerfile
│   └── extras │   └── extras
│   └── .gitkeep │   └── .gitkeep
├── common-settings.yml ├── common-settings.yaml
├── docker-compose.override.yml ├── compose.override.yaml
├── docker-compose.yml ├── compose.yaml
├── env ├── env
│   └── fqdn_context.env.example │   └── fqdn_context.env.example
└── README.md └── README.md
@@ -214,9 +214,9 @@ Make some code changes, for example to the Docker Compose Cookiecutter template.
│   ├── Dockerfile │   ├── Dockerfile
│   └── extras │   └── extras
│   └── .gitkeep │   └── .gitkeep
├── common-settings.yml ├── common-settings.yaml
├── docker-compose.override.yml ├── compose.override.yaml
├── docker-compose.yml ├── compose.yaml
├── env ├── env
│   └── fqdn_context.env.example │   └── fqdn_context.env.example
└── README.md └── README.md

View File

@@ -34,7 +34,7 @@ Your four answers translate as follows into rendered files.
│   ├── Dockerfile │   ├── Dockerfile
... ...
``` ```
2. The `service` variable by default copies your `project_slug` answer. It's a style decision whether you leave it at that and just hit `Enter`. The service name will come up in rendered `docker-compose.yml` at purely cosmetic locations such as the `networks:` key, `container_name:` and `/opt/docker-data` volume mount presets, here with `ftp` as the service name: 2. The `service` variable by default copies your `project_slug` answer. It's a style decision whether you leave it at that and just hit `Enter`. The service name will come up in rendered `compose.yaml` at purely cosmetic locations such as the `networks:` key, `container_name:` and `/opt/docker-data` volume mount presets, here with `ftp` as the service name:
``` ```
services: services:
mysql: mysql:
@@ -92,9 +92,9 @@ Above example of a multi-component (two in this case) `grafana` service will giv
│   ├── Dockerfile │   ├── Dockerfile
│   └── extras │   └── extras
│   └── .gitkeep │   └── .gitkeep
├── common-settings.yml ├── common-settings.yaml
├── docker-compose.override.yml ├── compose.override.yaml
├── docker-compose.yml ├── compose.yaml
├── env ├── env
│   └── fqdn_context.env.example │   └── fqdn_context.env.example
└── README.md └── README.md
@@ -113,9 +113,9 @@ With an alternative single-component `hashicorpvault` service the result may loo
│   ├── Dockerfile │   ├── Dockerfile
│   └── extras │   └── extras
│   └── .gitkeep │   └── .gitkeep
├── common-settings.yml ├── common-settings.yaml
├── docker-compose.override.yml ├── compose.override.yaml
├── docker-compose.yml ├── compose.yaml
├── env ├── env
│   └── fqdn_context.env.example │   └── fqdn_context.env.example
└── README.md └── README.md
@@ -126,7 +126,7 @@ Check out file contents over in the [examples/hashicorpvault](examples/hashicorp
Consider Cookiecutter's project directory and rendered files a starting point. It won't do everything perfectly. Consider Cookiecutter's project directory and rendered files a starting point. It won't do everything perfectly.
Imagine if you will a service that consists of [Infinispan](https://infinispan.org/) among other things. In Docker Hub's content-addressable image store Infinispan's location is at `infinispan/server` so you obviously want that exact string with a forward slash to show up in your `docker-compose.yml` as the `image:` key's value, same with your `Dockerfile`. The `image:` key's value comes from what you enter in Cookiecutter's `component_list` prompt. Component strings are then used to also pre-fill the `volumes:` key. Imagine if you will a service that consists of [Infinispan](https://infinispan.org/) among other things. In Docker Hub's content-addressable image store Infinispan's location is at `infinispan/server` so you obviously want that exact string with a forward slash to show up in your `compose.yaml` as the `image:` key's value, same with your `Dockerfile`. The `image:` key's value comes from what you enter in Cookiecutter's `component_list` prompt. Component strings are then used to also pre-fill the `volumes:` key.
_**This**_ will cause obvious issues (but the `image:` key is kinda correct): _**This**_ will cause obvious issues (but the `image:` key is kinda correct):
``` ```

View File

@@ -1,6 +1,6 @@
# FIXME # FIXME
Search and replace all mentions of FIXME with sensible content in this file and in [docker-compose.yml](docker-compose.yml). Search and replace all mentions of FIXME with sensible content in this file and in [compose.yaml](compose.yaml).
# Grafana Docker Compose files # Grafana Docker Compose files
@@ -18,7 +18,7 @@ When everything's ready start Grafana with Docker Compose, otherwise head down t
export COMPOSE_DIR='/opt/containers/grafana' export COMPOSE_DIR='/opt/containers/grafana'
export COMPOSE_CTX='ux_vilnius' export COMPOSE_CTX='ux_vilnius'
export COMPOSE_PROJECT='grafana-'"${COMPOSE_CTX}" export COMPOSE_PROJECT='grafana-'"${COMPOSE_CTX}"
export COMPOSE_FILE="${COMPOSE_DIR}"'/docker-compose.yml' export COMPOSE_FILE="${COMPOSE_DIR}"'/compose.yaml'
export COMPOSE_ENV=<add accordingly> export COMPOSE_ENV=<add accordingly>
``` ```
@@ -39,18 +39,22 @@ docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --en
## Copy to target ## Copy to target
Copy images to target Docker host, that is assuming you deploy to a machine that itself has no network route to reach Docker Hub. Copying in its simplest form involves a local `docker save` and a remote `docker load`. Consider the helper mini-project [quico.space/Quico/copy-docker](https://quico.space/Quico/copy-docker) where [copy-docker.sh](https://quico.space/Quico/copy-docker/src/branch/main/copy-docker.sh) allows the following workflow: Copy images to target Docker host, that is assuming you deploy to a machine that itself has no network route to reach Docker Hub or your private registry of choice. Copying in its simplest form involves a local `docker save` and a remote `docker load`. Consider the helper mini-project [quico.space/Quico/copy-docker](https://quico.space/Quico/copy-docker) where [copy-docker.sh](https://quico.space/Quico/copy-docker/src/branch/main/copy-docker.sh) allows the following workflow:
``` ```
source "${COMPOSE_ENV}" source "${COMPOSE_ENV}"
# FIXME Docker Hub image name with or without slash? FIXME # FIXME Docker Hub image name with or without slash? FIXME
for image in 'grafana:'"${GRAFANA_VERSION}" 'nginx:'"${NGINX_VERSION}"; do for image in 'grafana:'"${GRAFANA_VERSION}" 'nginx:'"${NGINX_VERSION}"; do
copy-docker.sh "${image}" fully.qualified.domain.name copy-docker "${image}" fully.qualified.domain.name
done done
``` ```
## Start ## Start
FIXME Does the service use a virtual IP address? FIXME
Make sure your service's virtual IP address is bound on your target host then start containers.
``` ```
docker --context 'fully.qualified.domain.name' compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --env-file "${COMPOSE_ENV}" --profile 'full' up --detach docker --context 'fully.qualified.domain.name' compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --env-file "${COMPOSE_ENV}" --profile 'full' up --detach
``` ```
@@ -77,7 +81,7 @@ Create ZFS datasets and set permissions as needed.
zfs create -p 'zpool/docker-data/grafana-'"${COMPOSE_CTX}"'/nginx/data/logs' zfs create -p 'zpool/docker-data/grafana-'"${COMPOSE_CTX}"'/nginx/data/logs'
zfs create -p 'zpool/docker-data/grafana-'"${COMPOSE_CTX}"'/nginx/config' zfs create -p 'zpool/docker-data/grafana-'"${COMPOSE_CTX}"'/nginx/config'
``` ```
FIXME When changing bind mount locations to real ones remember to also update `volumes:` in [docker-compose.yml](docker-compose.yml) FIXME FIXME When changing bind mount locations to real ones remember to also update `volumes:` in [compose.yaml](compose.yaml) FIXME
* Create subdirs * Create subdirs
``` ```
@@ -86,7 +90,7 @@ Create ZFS datasets and set permissions as needed.
* Change ownership * Change ownership
``` ```
chown -R 1000:1000 '/opt/docker-data/grafana-${COMPOSE_CTX}/grafana/data/'{*,.*} chown -R 1000:1000 '/opt/docker-data/grafana-'"${COMPOSE_CTX}"'/grafana/data/'*
``` ```
## Additional files ## Additional files

View File

@@ -1,6 +1,6 @@
# For the remainder of this Dockerfile EXAMPLE_ARG_FOR_DOCKERFILE will be # For the remainder of this Dockerfile EXAMPLE_ARG_FOR_DOCKERFILE will be
# available with a value of 'must_be_available_in_dockerfile', check out the env # available with a value of 'must_be_available_in_dockerfile', check out the env
# file at 'env/fully.qualified.domain.name.example' for reference. # file at 'env/fqdn_context.env.example' for reference.
# ARG EXAMPLE_ARG_FOR_DOCKERFILE # ARG EXAMPLE_ARG_FOR_DOCKERFILE
# Another env var, this one's needed in the example build step below: # Another env var, this one's needed in the example build step below:

View File

@@ -1,6 +1,6 @@
# For the remainder of this Dockerfile EXAMPLE_ARG_FOR_DOCKERFILE will be # For the remainder of this Dockerfile EXAMPLE_ARG_FOR_DOCKERFILE will be
# available with a value of 'must_be_available_in_dockerfile', check out the env # available with a value of 'must_be_available_in_dockerfile', check out the env
# file at 'env/fully.qualified.domain.name.example' for reference. # file at 'env/fqdn_context.env.example' for reference.
# ARG EXAMPLE_ARG_FOR_DOCKERFILE # ARG EXAMPLE_ARG_FOR_DOCKERFILE
# Another env var, this one's needed in the example build step below: # Another env var, this one's needed in the example build step below:

View File

@@ -1,5 +1,6 @@
services: services:
grafana-build: grafana-build:
# FIXME image name with or without slash? Docker Hub or private registry? With or without *_BUILD_DATE? FIXME
image: "grafana:${GRAFANA_VERSION}" image: "grafana:${GRAFANA_VERSION}"
profiles: ["build", "build-grafana"] profiles: ["build", "build-grafana"]
build: build:
@@ -9,6 +10,7 @@ services:
EXAMPLE_ARG_FOR_DOCKERFILE: "${EXAMPLE_ARG_FROM_ENV_FILE}" EXAMPLE_ARG_FOR_DOCKERFILE: "${EXAMPLE_ARG_FROM_ENV_FILE}"
GRAFANA_VERSION: "${GRAFANA_VERSION}" GRAFANA_VERSION: "${GRAFANA_VERSION}"
nginx-build: nginx-build:
# FIXME image name with or without slash? Docker Hub or private registry? With or without *_BUILD_DATE? FIXME
image: "nginx:${NGINX_VERSION}" image: "nginx:${NGINX_VERSION}"
profiles: ["build", "build-nginx"] profiles: ["build", "build-nginx"]
build: build:

View File

@@ -1,6 +1,6 @@
services: services:
grafana: grafana:
# FIXME Docker Hub image name with or without slash? FIXME # FIXME image name with or without slash? Docker Hub or private registry? With or without *_BUILD_DATE? FIXME
image: "grafana:${GRAFANA_VERSION}" image: "grafana:${GRAFANA_VERSION}"
container_name: "grafana-grafana-${CONTEXT}" container_name: "grafana-grafana-${CONTEXT}"
networks: networks:
@@ -10,12 +10,12 @@ services:
nginx: nginx:
condition: service_healthy condition: service_healthy
ulimits: ulimits:
nproc: ${ULIMIT_NPROC-65535} nproc: ${ULIMIT_NPROC:-65535}
nofile: nofile:
soft: ${ULIMIT_NPROC-65535} soft: ${ULIMIT_NPROC:-65535}
hard: ${ULIMIT_NPROC-65535} hard: ${ULIMIT_NPROC:-65535}
extends: extends:
file: common-settings.yml file: common-settings.yaml
service: common-settings service: common-settings
ports: ports:
# - "8080:80" # - "8080:80"
@@ -29,7 +29,7 @@ services:
# GRAFANA_USER: ${GRAFANA_USER} # GRAFANA_USER: ${GRAFANA_USER}
# GRAFANA_PASSWORD: ${GRAFANA_PASSWORD} # GRAFANA_PASSWORD: ${GRAFANA_PASSWORD}
nginx: nginx:
# FIXME Docker Hub image name with or without slash? FIXME # FIXME image name with or without slash? Docker Hub or private registry? With or without *_BUILD_DATE? FIXME
image: "nginx:${NGINX_VERSION}" image: "nginx:${NGINX_VERSION}"
container_name: "grafana-nginx-${CONTEXT}" container_name: "grafana-nginx-${CONTEXT}"
networks: networks:
@@ -42,12 +42,12 @@ services:
retries: 60 retries: 60
start_period: 2s start_period: 2s
ulimits: ulimits:
nproc: ${ULIMIT_NPROC-65535} nproc: ${ULIMIT_NPROC:-65535}
nofile: nofile:
soft: ${ULIMIT_NPROC-65535} soft: ${ULIMIT_NPROC:-65535}
hard: ${ULIMIT_NPROC-65535} hard: ${ULIMIT_NPROC:-65535}
extends: extends:
file: common-settings.yml file: common-settings.yaml
service: common-settings service: common-settings
ports: ports:
# - "8080:80" # - "8080:80"

View File

@@ -7,6 +7,7 @@ CONTEXT=ux_vilnius
# GRAFANA_VERSION=x.y.z # GRAFANA_VERSION=x.y.z
# NGINX_VERSION=x.y.z # NGINX_VERSION=x.y.z
# GRAFANA_VIP=10.1.1.2 # GRAFANA_VIP=10.1.1.2
# GRAFANA_BUILD_DATE=20230731
@@ -27,7 +28,7 @@ SUBNET=172.30.95.0/24
# See 'docker-compose.override.yml' for how to make a variable available in # See 'compose.override.yaml' for how to make a variable available in
# a Dockerfile # a Dockerfile
# --- # ---
# EXAMPLE_ARG_FROM_ENV_FILE=must_be_available_in_dockerfile # EXAMPLE_ARG_FROM_ENV_FILE=must_be_available_in_dockerfile

View File

@@ -1,6 +1,6 @@
# FIXME # FIXME
Search and replace all mentions of FIXME with sensible content in this file and in [docker-compose.yml](docker-compose.yml). Search and replace all mentions of FIXME with sensible content in this file and in [compose.yaml](compose.yaml).
# Vault Docker Compose files # Vault Docker Compose files
@@ -18,8 +18,8 @@ When everything's ready start Vault with Docker Compose, otherwise head down to
export COMPOSE_DIR='/opt/containers/hashicorpvault' export COMPOSE_DIR='/opt/containers/hashicorpvault'
export COMPOSE_CTX='ux_vilnius' export COMPOSE_CTX='ux_vilnius'
export COMPOSE_PROJECT='vault-'"${COMPOSE_CTX}" export COMPOSE_PROJECT='vault-'"${COMPOSE_CTX}"
export COMPOSE_FILE="${COMPOSE_DIR}"'/docker-compose.yml' export COMPOSE_FILE="${COMPOSE_DIR}"'/compose.yaml'
export COMPOSE_OVERRIDE="${COMPOSE_DIR%/}"'/docker-compose.override.yml' export COMPOSE_OVERRIDE="${COMPOSE_DIR%/}"'/compose.override.yaml'
export COMPOSE_ENV=<add accordingly> export COMPOSE_ENV=<add accordingly>
``` ```
@@ -32,15 +32,30 @@ docker context create fully.qualified.domain.name --docker 'host=ssh://root@full
## Build ## Build
> Skip to [Pull](#pull) if you already have images in your private registry ready to use. Otherwise read on to build them now.
FIXME We build the `vault` image locally. Our adjustment to the official image is simply adding `/tmp/vault` to it. See [build-context/Dockerfile](build-context/Dockerfile). We use `/tmp/vault` to bind-mount a dedicated ZFS dataset for the application's `tmpdir` location. FIXME We build the `vault` image locally. Our adjustment to the official image is simply adding `/tmp/vault` to it. See [build-context/Dockerfile](build-context/Dockerfile). We use `/tmp/vault` to bind-mount a dedicated ZFS dataset for the application's `tmpdir` location.
``` ```
docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --file "${COMPOSE_OVERRIDE}" --env-file "${COMPOSE_ENV}" --profile 'build-vault' build docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --file "${COMPOSE_OVERRIDE}" --env-file "${COMPOSE_ENV}" --profile 'build' build
```
## Push
Push to Docker Hub or your private registry. Setting up a private registry is out of scope of this repo. Once you have a registry available you can use it like so:
- On your OS install a Docker credential helper per [github.com/docker/docker-credential-helpers](https://github.com/docker/docker-credential-helpers). This will make sure you won't store credentials hashed (and unencrypted) in `~/.docker/config.json`. On an example Arch Linux machine where D-Bus Secret Service exists this will come via something like the [docker-credential-secretservice-bin](https://aur.archlinux.org/packages/docker-credential-secretservice-bin) Arch User Repository package. Just install and you're done.
- Do a `docker login registry.example.com`, enter username and password, confirm login.
```
source "${COMPOSE_ENV}"
docker push "registry.example.com/project/vault:${VAULT_BUILD_DATE}-${VAULT_VERSION}"
``` ```
## Pull ## Pull
FIXME Rewrite either [Build](#build) or this paragraph for which images are built and which ones pulled, `--profile 'full'` may not make sense FIXME Pull images from Docker Hub verbatim. > Skip this step if you just built images that still exist locally on your build host.
FIXME Rewrite either [Build](#build) or this paragraph for which images are built and which ones pulled, `--profile 'full'` may not make sense.
``` ```
docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --env-file "${COMPOSE_ENV}" --profile 'full' pull docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --env-file "${COMPOSE_ENV}" --profile 'full' pull
@@ -48,12 +63,12 @@ docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --en
## Copy to target ## Copy to target
Copy images to target Docker host, that is assuming you deploy to a machine that itself has no network route to reach Docker Hub. Copying in its simplest form involves a local `docker save` and a remote `docker load`. Consider the helper mini-project [quico.space/Quico/copy-docker](https://quico.space/Quico/copy-docker) where [copy-docker.sh](https://quico.space/Quico/copy-docker/src/branch/main/copy-docker.sh) allows the following workflow: Copy images to target Docker host, that is assuming you deploy to a machine that itself has no network route to reach Docker Hub or your private registry of choice. Copying in its simplest form involves a local `docker save` and a remote `docker load`. Consider the helper mini-project [quico.space/Quico/copy-docker](https://quico.space/Quico/copy-docker) where [copy-docker.sh](https://quico.space/Quico/copy-docker/src/branch/main/copy-docker.sh) allows the following workflow:
``` ```
source "${COMPOSE_ENV}" source "${COMPOSE_ENV}"
# FIXME Docker Hub image name with or without slash? FIXME # FIXME Docker Hub image name with or without slash? FIXME
copy-docker.sh 'vault:'"${VAULT_VERSION}" fully.qualified.domain.name copy-docker 'vault:'"${VAULT_VERSION}" fully.qualified.domain.name
``` ```
## Start ## Start
@@ -81,7 +96,7 @@ Create ZFS datasets and set permissions as needed.
zfs create -p 'zpool/docker-data/vault-'"${COMPOSE_CTX}"'/vault/data/logs' zfs create -p 'zpool/docker-data/vault-'"${COMPOSE_CTX}"'/vault/data/logs'
zfs create -p 'zpool/docker-data/vault-'"${COMPOSE_CTX}"'/vault/config' zfs create -p 'zpool/docker-data/vault-'"${COMPOSE_CTX}"'/vault/config'
``` ```
FIXME When changing bind mount locations to real ones remember to also update `volumes:` in [docker-compose.yml](docker-compose.yml) FIXME FIXME When changing bind mount locations to real ones remember to also update `volumes:` in [compose.yaml](compose.yaml) FIXME
* Create subdirs * Create subdirs
``` ```
@@ -90,7 +105,7 @@ Create ZFS datasets and set permissions as needed.
* Change ownership * Change ownership
``` ```
chown -R 1000:1000 '/opt/docker-data/vault-${COMPOSE_CTX}/vault/data/'{*,.*} chown -R 1000:1000 '/opt/docker-data/vault-'"${COMPOSE_CTX}"'/vault/data/'*
``` ```
## Additional files ## Additional files

View File

@@ -1,6 +1,6 @@
# For the remainder of this Dockerfile EXAMPLE_ARG_FOR_DOCKERFILE will be # For the remainder of this Dockerfile EXAMPLE_ARG_FOR_DOCKERFILE will be
# available with a value of 'must_be_available_in_dockerfile', check out the env # available with a value of 'must_be_available_in_dockerfile', check out the env
# file at 'env/fully.qualified.domain.name.example' for reference. # file at 'env/fqdn_context.env.example' for reference.
# ARG EXAMPLE_ARG_FOR_DOCKERFILE # ARG EXAMPLE_ARG_FOR_DOCKERFILE
# Another env var, this one's needed in the example build step below: # Another env var, this one's needed in the example build step below:

View File

@@ -1,9 +1,10 @@
services: services:
vault-build: vault-build:
image: "vault:${VAULT_VERSION}" # FIXME image name with or without slash? Docker Hub or private registry? With or without *_BUILD_DATE? FIXME
image: "registry.example.com/project/vault:${VAULT_BUILD_DATE}-${VAULT_VERSION}"
profiles: ["build"] profiles: ["build"]
build: build:
context: "build-context/vault" context: "build-context"
dockerfile: Dockerfile dockerfile: Dockerfile
args: args:
EXAMPLE_ARG_FOR_DOCKERFILE: "${EXAMPLE_ARG_FROM_ENV_FILE}" EXAMPLE_ARG_FOR_DOCKERFILE: "${EXAMPLE_ARG_FROM_ENV_FILE}"

View File

@@ -1,17 +1,17 @@
services: services:
vault: vault:
# FIXME Docker Hub image name with or without slash? FIXME # FIXME image name with or without slash? Docker Hub or private registry? With or without *_BUILD_DATE? FIXME
image: "vault:${VAULT_VERSION}" image: "registry.example.com/project/vault:${VAULT_BUILD_DATE}-${VAULT_VERSION}"
container_name: "vault-${CONTEXT}" container_name: "vault-${CONTEXT}"
networks: networks:
vault-default: vault-default:
ulimits: ulimits:
nproc: ${ULIMIT_NPROC-65535} nproc: ${ULIMIT_NPROC:-65535}
nofile: nofile:
soft: ${ULIMIT_NPROC-65535} soft: ${ULIMIT_NPROC:-65535}
hard: ${ULIMIT_NPROC-65535} hard: ${ULIMIT_NPROC:-65535}
extends: extends:
file: common-settings.yml file: common-settings.yaml
service: common-settings service: common-settings
ports: ports:
# - "8080:80" # - "8080:80"

View File

@@ -6,6 +6,7 @@ CONTEXT=ux_vilnius
# --- # ---
# VAULT_VERSION=x.y.z # VAULT_VERSION=x.y.z
# VAULT_VIP=10.1.1.2 # VAULT_VIP=10.1.1.2
# VAULT_BUILD_DATE=20230731
@@ -26,7 +27,7 @@ SUBNET=172.30.95.0/24
# See 'docker-compose.override.yml' for how to make a variable available in # See 'compose.override.yaml' for how to make a variable available in
# a Dockerfile # a Dockerfile
# --- # ---
# EXAMPLE_ARG_FROM_ENV_FILE=must_be_available_in_dockerfile # EXAMPLE_ARG_FROM_ENV_FILE=must_be_available_in_dockerfile

View File

@@ -1,6 +1,6 @@
# FIXME # FIXME
Search and replace all mentions of FIXME with sensible content in this file and in [docker-compose.yml](docker-compose.yml). Search and replace all mentions of FIXME with sensible content in this file and in [compose.yaml](compose.yaml).
# {{ cookiecutter.__service_slug.capitalize() }} Docker Compose files # {{ cookiecutter.__service_slug.capitalize() }} Docker Compose files
@@ -18,8 +18,8 @@ When everything's ready start {{ cookiecutter.__service_slug.capitalize() }} wit
export COMPOSE_DIR='/opt/containers/{{ cookiecutter.__project_slug }}' export COMPOSE_DIR='/opt/containers/{{ cookiecutter.__project_slug }}'
export COMPOSE_CTX='ux_vilnius' export COMPOSE_CTX='ux_vilnius'
export COMPOSE_PROJECT='{{ cookiecutter.__service_slug }}-'"${COMPOSE_CTX}" export COMPOSE_PROJECT='{{ cookiecutter.__service_slug }}-'"${COMPOSE_CTX}"
export COMPOSE_FILE="${COMPOSE_DIR}"'/docker-compose.yml'{% if cookiecutter.build == "yes" %} export COMPOSE_FILE="${COMPOSE_DIR}"'/compose.yaml'{% if cookiecutter.build == "yes" %}
export COMPOSE_OVERRIDE="${COMPOSE_DIR%/}"'/docker-compose.override.yml'{% endif %} export COMPOSE_OVERRIDE="${COMPOSE_DIR%/}"'/compose.override.yaml'{% endif %}
export COMPOSE_ENV=<add accordingly> export COMPOSE_ENV=<add accordingly>
``` ```
@@ -33,21 +33,43 @@ docker context create fully.qualified.domain.name --docker 'host=ssh://root@full
{%- if cookiecutter.build == "yes" %} {%- if cookiecutter.build == "yes" %}
## Build ## Build
{%- set components = cookiecutter.__component_list_slug.split(',') -%} {% set components = cookiecutter.__component_list_slug.split(',') -%}
{% for component in components %} {%- for component in components %}
{% if loop.first %} {%- if loop.first %}
> Skip to [Pull](#pull) if you already have images in your private registry ready to use. Otherwise read on to build them now.
FIXME We build the `{{ cookiecutter.__service_slug }}` image locally. Our adjustment to the official image is simply adding `/tmp/{{ cookiecutter.__service_slug }}` to it. See {% if ',' in cookiecutter.__component_list_slug %}[build-context/{{ cookiecutter.__service_slug }}/Dockerfile](build-context/{{ cookiecutter.__service_slug }}/Dockerfile){%- else %}[build-context/Dockerfile](build-context/Dockerfile){%- endif %}. We use `/tmp/{{ cookiecutter.__service_slug }}` to bind-mount a dedicated ZFS dataset for the application's `tmpdir` location. FIXME We build the `{{ cookiecutter.__service_slug }}` image locally. Our adjustment to the official image is simply adding `/tmp/{{ cookiecutter.__service_slug }}` to it. See {% if ',' in cookiecutter.__component_list_slug %}[build-context/{{ cookiecutter.__service_slug }}/Dockerfile](build-context/{{ cookiecutter.__service_slug }}/Dockerfile){%- else %}[build-context/Dockerfile](build-context/Dockerfile){%- endif %}. We use `/tmp/{{ cookiecutter.__service_slug }}` to bind-mount a dedicated ZFS dataset for the application's `tmpdir` location.
``` ```
docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --file "${COMPOSE_OVERRIDE}" --env-file "${COMPOSE_ENV}" --profile 'build-{{ cookiecutter.__service_slug }}' build docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --file "${COMPOSE_OVERRIDE}" --env-file "${COMPOSE_ENV}" --profile 'build{% if ',' in cookiecutter.__component_list_slug %}-{{ cookiecutter.__service_slug }}{%- endif %}' build
``` ```
{%- endif %} {%- endif %}
{%- endfor %} {% endfor %}
## Push
Push to Docker Hub or your private registry. Setting up a private registry is out of scope of this repo. Once you have a registry available you can use it like so:
- On your OS install a Docker credential helper per [github.com/docker/docker-credential-helpers](https://github.com/docker/docker-credential-helpers). This will make sure you won't store credentials hashed (and unencrypted) in `~/.docker/config.json`. On an example Arch Linux machine where D-Bus Secret Service exists this will come via something like the [docker-credential-secretservice-bin](https://aur.archlinux.org/packages/docker-credential-secretservice-bin) Arch User Repository package. Just install and you're done.
- Do a `docker login registry.example.com`, enter username and password, confirm login.
```
source "${COMPOSE_ENV}"
{%- set components = cookiecutter.__component_list_slug.split(',') -%}
{%- if ',' in cookiecutter.__component_list_slug %}
for image in{% for component in components %} \
'{%- if cookiecutter.build == "yes" -%}{%- if loop.first -%}registry.example.com/project/{%- endif -%}{%- endif -%}{{ component }}:'"{%- if cookiecutter.build == "yes" -%}{%- if loop.first -%}${% raw %}{{% endraw %}{{ component.upper() }}_BUILD_DATE{% raw %}}{% endraw %}-{%- endif -%}{%- endif -%}${% raw %}{{% endraw %}{{ component.upper() }}_VERSION{% raw %}}{% endraw %}"{%- endfor %}; do
docker push 'registry.example.com/project/'"${image}"
done
{%- else %}
docker push "{%- if cookiecutter.build == "yes" -%}registry.example.com/project/{%- endif -%}{{ cookiecutter.__component_list_slug }}:{%- if cookiecutter.build == "yes" -%}${% raw %}{{% endraw %}{{ cookiecutter.__component_list_slug.upper() }}_BUILD_DATE{% raw %}}{% endraw %}-{%- endif -%}${% raw %}{{% endraw %}{{ cookiecutter.__component_list_slug.upper() }}_VERSION{% raw %}}{% endraw %}"
{%- endif %}
```
{%- endif %} {%- endif %}
## Pull ## Pull
{% if cookiecutter.build == "yes" %}FIXME Rewrite either [Build](#build) or this paragraph for which images are built and which ones pulled, `--profile 'full'` may not make sense FIXME {% endif %}Pull images from Docker Hub verbatim. {% if cookiecutter.build == "yes" %}> Skip this step if you just built images that still exist locally on your build host.
FIXME Rewrite either [Build](#build) or this paragraph for which images are built and which ones pulled, `--profile 'full'` may not make sense.{% else %}Pull images from Docker Hub verbatim.{% endif %}
``` ```
docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --env-file "${COMPOSE_ENV}" --profile 'full' pull docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --env-file "${COMPOSE_ENV}" --profile 'full' pull
@@ -55,7 +77,7 @@ docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --en
## Copy to target ## Copy to target
Copy images to target Docker host, that is assuming you deploy to a machine that itself has no network route to reach Docker Hub. Copying in its simplest form involves a local `docker save` and a remote `docker load`. Consider the helper mini-project [quico.space/Quico/copy-docker](https://quico.space/Quico/copy-docker) where [copy-docker.sh](https://quico.space/Quico/copy-docker/src/branch/main/copy-docker.sh) allows the following workflow: Copy images to target Docker host, that is assuming you deploy to a machine that itself has no network route to reach Docker Hub or your private registry of choice. Copying in its simplest form involves a local `docker save` and a remote `docker load`. Consider the helper mini-project [quico.space/Quico/copy-docker](https://quico.space/Quico/copy-docker) where [copy-docker.sh](https://quico.space/Quico/copy-docker/src/branch/main/copy-docker.sh) allows the following workflow:
``` ```
source "${COMPOSE_ENV}" source "${COMPOSE_ENV}"
@@ -63,15 +85,23 @@ source "${COMPOSE_ENV}"
{%- set components = cookiecutter.__component_list_slug.split(',') -%} {%- set components = cookiecutter.__component_list_slug.split(',') -%}
{%- if ',' in cookiecutter.__component_list_slug %} {%- if ',' in cookiecutter.__component_list_slug %}
for image in{% for component in components %} '{{ component }}:'"${% raw %}{{% endraw %}{{ component.upper() }}_VERSION{% raw %}}{% endraw %}"{%- endfor %}; do for image in{% for component in components %} '{{ component }}:'"${% raw %}{{% endraw %}{{ component.upper() }}_VERSION{% raw %}}{% endraw %}"{%- endfor %}; do
copy-docker.sh "${image}" fully.qualified.domain.name copy-docker "${image}" fully.qualified.domain.name
done done
{%- else %} {%- else %}
copy-docker.sh '{{ cookiecutter.__component_list_slug }}:'"${% raw %}{{% endraw %}{{ cookiecutter.__component_list_slug.upper() }}_VERSION{% raw %}}{% endraw %}" fully.qualified.domain.name copy-docker '{{ cookiecutter.__component_list_slug }}:'"${% raw %}{{% endraw %}{{ cookiecutter.__component_list_slug.upper() }}_VERSION{% raw %}}{% endraw %}" fully.qualified.domain.name
{%- endif %} {%- endif %}
``` ```
## Start ## Start
{%- if ',' in cookiecutter.__component_list_slug %}
FIXME Does the service use a virtual IP address? FIXME
Make sure your service's virtual IP address is bound on your target host then start containers.
{%- endif %}
``` ```
{%- if ',' in cookiecutter.__component_list_slug %} {%- if ',' in cookiecutter.__component_list_slug %}
docker --context 'fully.qualified.domain.name' compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --env-file "${COMPOSE_ENV}" --profile 'full' up --detach docker --context 'fully.qualified.domain.name' compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --env-file "${COMPOSE_ENV}" --profile 'full' up --detach
@@ -108,7 +138,7 @@ Create ZFS datasets and set permissions as needed.
zfs create -p 'zpool/docker-data/{{ cookiecutter.__service_slug }}-'"${COMPOSE_CTX}"'/{{ cookiecutter.__service_slug }}/config' zfs create -p 'zpool/docker-data/{{ cookiecutter.__service_slug }}-'"${COMPOSE_CTX}"'/{{ cookiecutter.__service_slug }}/config'
{%- endif %} {%- endif %}
``` ```
FIXME When changing bind mount locations to real ones remember to also update `volumes:` in [docker-compose.yml](docker-compose.yml) FIXME FIXME When changing bind mount locations to real ones remember to also update `volumes:` in [compose.yaml](compose.yaml) FIXME
* Create subdirs * Create subdirs
``` ```
@@ -125,7 +155,7 @@ Create ZFS datasets and set permissions as needed.
{%- set components = cookiecutter.__component_list_slug.split(',') -%} {%- set components = cookiecutter.__component_list_slug.split(',') -%}
{% for component in components %} {% for component in components %}
{%- if loop.first %} {%- if loop.first %}
chown -R 1000:1000 '/opt/docker-data/{{ cookiecutter.__service_slug }}-${COMPOSE_CTX}/{{ cookiecutter.__service_slug }}/data/'{*,.*} chown -R 1000:1000 '/opt/docker-data/{{ cookiecutter.__service_slug }}-'"${COMPOSE_CTX}"'/{{ cookiecutter.__service_slug }}/data/'*
{%- endif %} {%- endif %}
{%- endfor %} {%- endfor %}
``` ```

View File

@@ -1,6 +1,6 @@
# For the remainder of this Dockerfile EXAMPLE_ARG_FOR_DOCKERFILE will be # For the remainder of this Dockerfile EXAMPLE_ARG_FOR_DOCKERFILE will be
# available with a value of 'must_be_available_in_dockerfile', check out the env # available with a value of 'must_be_available_in_dockerfile', check out the env
# file at 'env/fully.qualified.domain.name.example' for reference. # file at 'env/fqdn_context.env.example' for reference.
# ARG EXAMPLE_ARG_FOR_DOCKERFILE # ARG EXAMPLE_ARG_FOR_DOCKERFILE
# Another env var, this one's needed in the example build step below: # Another env var, this one's needed in the example build step below:

View File

@@ -0,0 +1,27 @@
services:
{%- if ',' in cookiecutter.__component_list_slug -%}
{%- set components = cookiecutter.__component_list_slug.split(',') -%}
{% for component in components %}
{{ component }}-build:
# FIXME image name with or without slash? Docker Hub or private registry? With or without *_BUILD_DATE? FIXME
image: "{%- if cookiecutter.build == "yes" -%}{%- if loop.first -%}registry.example.com/project/{%- endif -%}{%- endif -%}{{ component }}:{%- if cookiecutter.build == "yes" -%}{%- if loop.first -%}${% raw %}{{% endraw %}{{ component.upper() }}_BUILD_DATE{% raw %}}{% endraw %}-{%- endif -%}{%- endif -%}${% raw %}{{% endraw %}{{ component.upper() }}_VERSION{% raw %}}{% endraw %}"
profiles: ["build", "build-{{ component }}"]
build:
context: "build-context/{{ component }}"
dockerfile: Dockerfile
args:
EXAMPLE_ARG_FOR_DOCKERFILE: "${EXAMPLE_ARG_FROM_ENV_FILE}"
{{ component.upper() }}_VERSION: "${% raw %}{{% endraw %}{{ component.upper() }}_VERSION{% raw %}}{% endraw %}"
{%- endfor %}
{%- else %}
{{ cookiecutter.__component_list_slug }}-build:
# FIXME image name with or without slash? Docker Hub or private registry? With or without *_BUILD_DATE? FIXME
image: "{%- if cookiecutter.build == "yes" -%}registry.example.com/project/{%- endif -%}{{ cookiecutter.__component_list_slug }}:{%- if cookiecutter.build == "yes" -%}${% raw %}{{% endraw %}{{ cookiecutter.__component_list_slug.upper() }}_BUILD_DATE{% raw %}}{% endraw %}-{%- endif -%}${% raw %}{{% endraw %}{{ cookiecutter.__component_list_slug.upper() }}_VERSION{% raw %}}{% endraw %}"
profiles: ["build"]
build:
context: "build-context"
dockerfile: Dockerfile
args:
EXAMPLE_ARG_FOR_DOCKERFILE: "${EXAMPLE_ARG_FROM_ENV_FILE}"
{{ cookiecutter.__component_list_slug.upper() }}_VERSION: "${% raw %}{{% endraw %}{{ cookiecutter.__component_list_slug.upper() }}_VERSION{% raw %}}{% endraw %}"
{%- endif %}

View File

@@ -12,8 +12,8 @@ services:
{%- endfor -%} {%- endfor -%}
{%- for component in components %} {%- for component in components %}
{{ component }}: {{ component }}:
# FIXME Docker Hub image name with or without slash? FIXME # FIXME image name with or without slash? Docker Hub or private registry? With or without *_BUILD_DATE? FIXME
image: "{{ component }}:${% raw %}{{% endraw %}{{ component.upper() }}_VERSION{% raw %}}{% endraw %}" image: "{%- if cookiecutter.build == "yes" -%}{%- if loop.first -%}registry.example.com/project/{%- endif -%}{%- endif -%}{{ component }}:{%- if cookiecutter.build == "yes" -%}{%- if loop.first -%}${% raw %}{{% endraw %}{{ component.upper() }}_BUILD_DATE{% raw %}}{% endraw %}-{%- endif -%}{%- endif -%}${% raw %}{{% endraw %}{{ component.upper() }}_VERSION{% raw %}}{% endraw %}"
container_name: "{{ cookiecutter.__service_slug }}-{{ component }}-${CONTEXT}" container_name: "{{ cookiecutter.__service_slug }}-{{ component }}-${CONTEXT}"
networks: networks:
{{ cookiecutter.__service_slug }}-default: {{ cookiecutter.__service_slug }}-default:
@@ -31,12 +31,12 @@ services:
start_period: 2s start_period: 2s
{%- endif %} {%- endif %}
ulimits: ulimits:
nproc: ${ULIMIT_NPROC-65535} nproc: ${ULIMIT_NPROC:-65535}
nofile: nofile:
soft: ${ULIMIT_NPROC-65535} soft: ${ULIMIT_NPROC:-65535}
hard: ${ULIMIT_NPROC-65535} hard: ${ULIMIT_NPROC:-65535}
extends: extends:
file: common-settings.yml file: common-settings.yaml
service: common-settings service: common-settings
ports: ports:
# - "8080:80" # - "8080:80"
@@ -52,18 +52,18 @@ services:
{%- endfor -%} {%- endfor -%}
{%- else %} {%- else %}
{{ cookiecutter.__component_list_slug }}: {{ cookiecutter.__component_list_slug }}:
# FIXME Docker Hub image name with or without slash? FIXME # FIXME image name with or without slash? Docker Hub or private registry? With or without *_BUILD_DATE? FIXME
image: "{{ cookiecutter.__component_list_slug }}:${% raw %}{{% endraw %}{{ cookiecutter.__component_list_slug.upper() }}_VERSION{% raw %}}{% endraw %}" image: "{%- if cookiecutter.build == "yes" -%}registry.example.com/project/{%- endif -%}{{ cookiecutter.__component_list_slug }}:{%- if cookiecutter.build == "yes" -%}${% raw %}{{% endraw %}{{ cookiecutter.__component_list_slug.upper() }}_BUILD_DATE{% raw %}}{% endraw %}-{%- endif -%}${% raw %}{{% endraw %}{{ cookiecutter.__component_list_slug.upper() }}_VERSION{% raw %}}{% endraw %}"
container_name: "{{ cookiecutter.__service_slug }}-${CONTEXT}" container_name: "{{ cookiecutter.__service_slug }}-${CONTEXT}"
networks: networks:
{{ cookiecutter.__service_slug }}-default: {{ cookiecutter.__service_slug }}-default:
ulimits: ulimits:
nproc: ${ULIMIT_NPROC-65535} nproc: ${ULIMIT_NPROC:-65535}
nofile: nofile:
soft: ${ULIMIT_NPROC-65535} soft: ${ULIMIT_NPROC:-65535}
hard: ${ULIMIT_NPROC-65535} hard: ${ULIMIT_NPROC:-65535}
extends: extends:
file: common-settings.yml file: common-settings.yaml
service: common-settings service: common-settings
ports: ports:
# - "8080:80" # - "8080:80"

View File

@@ -1,25 +0,0 @@
services:
{%- if ',' in cookiecutter.__component_list_slug -%}
{%- set components = cookiecutter.__component_list_slug.split(',') -%}
{% for component in components %}
{{ component }}-build:
image: "{{ component }}:${% raw %}{{% endraw %}{{ component.upper() }}_VERSION{% raw %}}{% endraw %}"
profiles: ["build", "build-{{ component }}"]
build:
context: "build-context/{{ component }}"
dockerfile: Dockerfile
args:
EXAMPLE_ARG_FOR_DOCKERFILE: "${EXAMPLE_ARG_FROM_ENV_FILE}"
{{ component.upper() }}_VERSION: "${% raw %}{{% endraw %}{{ component.upper() }}_VERSION{% raw %}}{% endraw %}"
{%- endfor %}
{%- else %}
{{ cookiecutter.__component_list_slug }}-build:
image: "{{ cookiecutter.__component_list_slug }}:${% raw %}{{% endraw %}{{ cookiecutter.__component_list_slug.upper() }}_VERSION{% raw %}}{% endraw %}"
profiles: ["build"]
build:
context: "build-context/{{ cookiecutter.__component_list_slug }}"
dockerfile: Dockerfile
args:
EXAMPLE_ARG_FOR_DOCKERFILE: "${EXAMPLE_ARG_FROM_ENV_FILE}"
{{ cookiecutter.__component_list_slug.upper() }}_VERSION: "${% raw %}{{% endraw %}{{ cookiecutter.__component_list_slug.upper() }}_VERSION{% raw %}}{% endraw %}"
{%- endif %}

View File

@@ -11,6 +11,7 @@ CONTEXT=ux_vilnius
{%- for component in components %} {%- for component in components %}
{%- if loop.first %} {%- if loop.first %}
# {{ component.upper() }}_VIP=10.1.1.2 # {{ component.upper() }}_VIP=10.1.1.2
# {{ component.upper() }}_BUILD_DATE=20230731
{%- endif %} {%- endif %}
{%- endfor %} {%- endfor %}
@@ -33,7 +34,7 @@ SUBNET=172.30.95.0/24
# See 'docker-compose.override.yml' for how to make a variable available in # See 'compose.override.yaml' for how to make a variable available in
# a Dockerfile # a Dockerfile
# --- # ---
# EXAMPLE_ARG_FROM_ENV_FILE=must_be_available_in_dockerfile # EXAMPLE_ARG_FROM_ENV_FILE=must_be_available_in_dockerfile