Compare commits
47 Commits
1995283c73
...
master
Author | SHA1 | Date | |
---|---|---|---|
da60952fe4 | |||
d6ea3f1853 | |||
adb7bf6795 | |||
215db1682d | |||
36f2eecba1 | |||
1f588e90bc | |||
b534a9bccf | |||
e5e78a0527 | |||
d98de5aff0 | |||
ffaf43e56f | |||
20d303e79a | |||
117627889f | |||
ab9b1009cb | |||
6605fe0866 | |||
782981c6f8 | |||
aef611f731 | |||
c6e93b353d | |||
e112d0ef8c | |||
387ef3bbbe | |||
31f67e3aad | |||
795585260a | |||
6c08ba37c6 | |||
e6b8f35906 | |||
692d115d5c | |||
0042adba00 | |||
96cce1634b | |||
40ab99bf87 | |||
c460559b34 | |||
9e9ec037b8 | |||
71a2fe1beb | |||
0436224728 | |||
e5dcc062de | |||
bb6777f389 | |||
467e98b01a | |||
161967ebac | |||
3026e30783 | |||
494228b367 | |||
024a056d9e | |||
0f4b7ac7a5 | |||
75b31844a0 | |||
19c38255a2 | |||
9fc23aa0b2 | |||
5c8cf16348 | |||
5645fba3e1 | |||
79dc452799 | |||
de2b657ec1 | |||
9ef85a53e6 |
15
README.md
15
README.md
@@ -33,7 +33,6 @@ This is Cookiecutter prompting for info:
|
|||||||
project_slug [dir-name]: grafana
|
project_slug [dir-name]: grafana
|
||||||
service [grafana]:
|
service [grafana]:
|
||||||
component_list [grafana]: grafana,nginx
|
component_list [grafana]: grafana,nginx
|
||||||
context [ctx]: cncf
|
|
||||||
Select build:
|
Select build:
|
||||||
1 - no
|
1 - no
|
||||||
2 - yes
|
2 - yes
|
||||||
@@ -57,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
|
||||||
@@ -190,7 +189,6 @@ Make some code changes, for example to the Docker Compose Cookiecutter template.
|
|||||||
project_slug [dir-name]: mydir
|
project_slug [dir-name]: mydir
|
||||||
service [mydir]: myservice
|
service [mydir]: myservice
|
||||||
component_list [myservice]: mycomponent_one,mycomponent_two
|
component_list [myservice]: mycomponent_one,mycomponent_two
|
||||||
context [ctx]: ux_novosibirsk
|
|
||||||
Select build:
|
Select build:
|
||||||
1 - no
|
1 - no
|
||||||
2 - yes
|
2 - yes
|
||||||
@@ -216,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
|
||||||
@@ -233,7 +231,6 @@ Make some code changes, for example to the Docker Compose Cookiecutter template.
|
|||||||
project_slug=mydir \
|
project_slug=mydir \
|
||||||
service=myservice \
|
service=myservice \
|
||||||
component_list=mycomponent_one,mycomponent_two \
|
component_list=mycomponent_one,mycomponent_two \
|
||||||
context=ux_novosibirsk \
|
|
||||||
build=yes
|
build=yes
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@@ -12,7 +12,6 @@ Cookiecutter interactively prompts you for the following info, here with example
|
|||||||
project_slug [dir-name]: grafana
|
project_slug [dir-name]: grafana
|
||||||
service [grafana]:
|
service [grafana]:
|
||||||
component_list [grafana]: grafana,nginx
|
component_list [grafana]: grafana,nginx
|
||||||
context [ctx]: cncf
|
|
||||||
Select build:
|
Select build:
|
||||||
1 - no
|
1 - no
|
||||||
2 - yes
|
2 - yes
|
||||||
@@ -35,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:
|
||||||
@@ -64,22 +63,7 @@ Your four answers translate as follows into rendered files.
|
|||||||
...
|
...
|
||||||
```
|
```
|
||||||
|
|
||||||
4. The `context` prompt is a generic string to help you distinguish deployments. It can be whatever you want such as for example a team name, here `cncf` which shows up as a preset in an example env file. It defaults to `ctx` just so it can't be empty.
|
4. Prompt `build` is a yes-no question. Cookiecutter will create a `README.md` file with copy-pastable Docker Compose commands pre-filled. If you answer `yes` to this prompt `README.md` will contain an example paragraph that explains the build process along the lines of:
|
||||||
```
|
|
||||||
.
|
|
||||||
└── grafana
|
|
||||||
...
|
|
||||||
└── env
|
|
||||||
└── fqdn_context.env.example <---
|
|
||||||
```
|
|
||||||
|
|
||||||
Which then looks like:
|
|
||||||
```
|
|
||||||
CONTEXT=cncf
|
|
||||||
...
|
|
||||||
```
|
|
||||||
|
|
||||||
5. Prompt `build` is a yes-no question. Cookiecutter will create a `README.md` file with copy-pastable Docker Compose commands pre-filled. If you answer `yes` to this prompt `README.md` will contain an example paragraph that explains the build process along the lines of:
|
|
||||||
```
|
```
|
||||||
docker compose ... --profile 'build' build
|
docker compose ... --profile 'build' build
|
||||||
```
|
```
|
||||||
@@ -108,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
|
||||||
@@ -129,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
|
||||||
@@ -142,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):
|
||||||
```
|
```
|
||||||
|
@@ -5,7 +5,5 @@
|
|||||||
"__service_slug": "{{ cookiecutter.service.lower().replace(' ', '_').replace('-', '_') }}",
|
"__service_slug": "{{ cookiecutter.service.lower().replace(' ', '_').replace('-', '_') }}",
|
||||||
"component_list": "{{ cookiecutter.__service_slug }}",
|
"component_list": "{{ cookiecutter.__service_slug }}",
|
||||||
"__component_list_slug": "{{ cookiecutter.component_list.lower().replace(' ', '_').replace('-', '_') }}",
|
"__component_list_slug": "{{ cookiecutter.component_list.lower().replace(' ', '_').replace('-', '_') }}",
|
||||||
"context": "ctx",
|
"build": ["yes", "no"]
|
||||||
"__context_slug": "{{ cookiecutter.context.lower().replace(' ', '_').replace('-', '_') }}",
|
|
||||||
"build": ["no", "yes"]
|
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,10 @@
|
|||||||
|
# FIXME
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
Docker Compose files to spin up an instance of Grafana.
|
Docker Compose files to spin up an instance of Grafana FIXME capitalization FIXME.
|
||||||
|
|
||||||
# How to run
|
# How to run
|
||||||
|
|
||||||
@@ -9,18 +13,50 @@ Add a `COMPOSE_ENV` file and save its location as a shell variable along with th
|
|||||||
When everything's ready start Grafana with Docker Compose, otherwise head down to [Initial setup](#initial-setup) first.
|
When everything's ready start Grafana with Docker Compose, otherwise head down to [Initial setup](#initial-setup) first.
|
||||||
|
|
||||||
## Environment
|
## Environment
|
||||||
|
|
||||||
```
|
```
|
||||||
export COMPOSE_DIR='/opt/containers/grafana'
|
export COMPOSE_DIR='/opt/containers/grafana'
|
||||||
export COMPOSE_CTX='cncf'
|
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>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
On your deployment machine create the necessary Docker context to connect to and control the Docker daemon on whatever target host you'll be using, for example:
|
||||||
|
```
|
||||||
|
docker context create fully.qualified.domain.name --docker 'host=ssh://root@fully.qualified.domain.name'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Pull
|
||||||
|
|
||||||
|
Pull images from Docker Hub verbatim.
|
||||||
|
|
||||||
|
```
|
||||||
|
docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --env-file "${COMPOSE_ENV}" --profile 'full' pull
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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 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}"
|
||||||
|
# FIXME Docker Hub image name with or without slash? FIXME
|
||||||
|
for image in 'grafana:'"${GRAFANA_VERSION}" 'nginx:'"${NGINX_VERSION}"; do
|
||||||
|
copy-docker "${image}" fully.qualified.domain.name
|
||||||
|
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 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
|
||||||
```
|
```
|
||||||
|
|
||||||
# Initial setup
|
# Initial setup
|
||||||
@@ -38,18 +74,69 @@ Create ZFS datasets and set permissions as needed.
|
|||||||
|
|
||||||
* Container-specific datasets
|
* Container-specific datasets
|
||||||
```
|
```
|
||||||
zfs create -p 'zpool/docker-data/grafana-${COMPOSE_CTX}/grafana/data/db'
|
zfs create -p 'zpool/docker-data/grafana-'"${COMPOSE_CTX}"'/grafana/data/db'
|
||||||
zfs create -p 'zpool/docker-data/grafana-${COMPOSE_CTX}/grafana/data/logs'
|
zfs create -p 'zpool/docker-data/grafana-'"${COMPOSE_CTX}"'/grafana/data/logs'
|
||||||
zfs create -p 'zpool/docker-data/grafana-${COMPOSE_CTX}/grafana/config'
|
zfs create -p 'zpool/docker-data/grafana-'"${COMPOSE_CTX}"'/grafana/config'
|
||||||
zfs create -p 'zpool/docker-data/grafana-${COMPOSE_CTX}/nginx/data/db'
|
zfs create -p 'zpool/docker-data/grafana-'"${COMPOSE_CTX}"'/nginx/data/db'
|
||||||
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 [compose.yaml](compose.yaml) FIXME
|
||||||
|
|
||||||
|
* Create subdirs
|
||||||
|
```
|
||||||
|
mkdir -p '/opt/docker-data/grafana-'"${COMPOSE_CTX}"'/grafana/'{'.ssh','config','data','projects'}
|
||||||
```
|
```
|
||||||
When changing bind mount locations to real ones remember to also update `volumes:` in [docker-compose.yml](docker-compose.yml).
|
|
||||||
|
|
||||||
* 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
|
||||||
|
|
||||||
|
Place the following files on target server. Use the directory structure at [build-context](build-context) as a guide, specifically at `docker-data`.
|
||||||
|
|
||||||
|
FIXME Add details about files that aren't self-explanatory FIXME
|
||||||
|
|
||||||
|
```
|
||||||
|
build-context/
|
||||||
|
├── grafana
|
||||||
|
│ ├── docker-data
|
||||||
|
│ | └── config
|
||||||
|
│ │ └── grafana.cfg
|
||||||
|
│ ├── ...
|
||||||
|
│ └── ...
|
||||||
|
└── nginx
|
||||||
|
├── docker-data
|
||||||
|
| └── config
|
||||||
|
│ └── nginx.cfg
|
||||||
|
├── ...
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
When done head back up to [How to run](#how-to-run).
|
When done head back up to [How to run](#how-to-run).
|
||||||
|
|
||||||
|
# Development
|
||||||
|
|
||||||
|
## Conventional commits
|
||||||
|
|
||||||
|
This project uses [Conventional Commits](https://www.conventionalcommits.org/) for its commit messages.
|
||||||
|
|
||||||
|
### Commit types
|
||||||
|
|
||||||
|
Commit _types_ besides `fix` and `feat` are:
|
||||||
|
|
||||||
|
- `refactor`: Keeping functionality while streamlining or otherwise improving function flow
|
||||||
|
- `docs`: Documentation for project or components
|
||||||
|
|
||||||
|
### Commit scopes
|
||||||
|
|
||||||
|
The following _scopes_ are known for this project. A Conventional Commits commit message may optionally use one of the following scopes or none:
|
||||||
|
|
||||||
|
- `grafana`: A change to how the `grafana` service component works
|
||||||
|
- `nginx`: A change to how the `nginx` service component works
|
||||||
|
- `build`: Build-related changes such as `Dockerfile` fixes and features.
|
||||||
|
- `mount`: Volume or bind mount-related changes.
|
||||||
|
- `net`: Networking, IP addressing, routing changes
|
||||||
|
- `meta`: Affects the project's repo layout, file names etc.
|
||||||
|
@@ -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:
|
||||||
|
@@ -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:
|
||||||
|
@@ -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:
|
@@ -1,5 +1,6 @@
|
|||||||
services:
|
services:
|
||||||
grafana:
|
grafana:
|
||||||
|
# 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:
|
||||||
@@ -8,8 +9,13 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
nginx:
|
nginx:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
|
ulimits:
|
||||||
|
nproc: ${ULIMIT_NPROC:-65535}
|
||||||
|
nofile:
|
||||||
|
soft: ${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"
|
||||||
@@ -23,6 +29,7 @@ services:
|
|||||||
# GRAFANA_USER: ${GRAFANA_USER}
|
# GRAFANA_USER: ${GRAFANA_USER}
|
||||||
# GRAFANA_PASSWORD: ${GRAFANA_PASSWORD}
|
# GRAFANA_PASSWORD: ${GRAFANA_PASSWORD}
|
||||||
nginx:
|
nginx:
|
||||||
|
# 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:
|
||||||
@@ -34,8 +41,13 @@ services:
|
|||||||
timeout: 1s
|
timeout: 1s
|
||||||
retries: 60
|
retries: 60
|
||||||
start_period: 2s
|
start_period: 2s
|
||||||
|
ulimits:
|
||||||
|
nproc: ${ULIMIT_NPROC:-65535}
|
||||||
|
nofile:
|
||||||
|
soft: ${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"
|
@@ -1,4 +1,4 @@
|
|||||||
CONTEXT=cncf
|
CONTEXT=ux_vilnius
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -7,14 +7,7 @@ CONTEXT=cncf
|
|||||||
# 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
|
||||||
|
|
||||||
|
|
||||||
# A ${LOCATION} var is usually not needed. It may be helpful when a ${CONTEXT}
|
|
||||||
# extends over more than one location e.g. to bind-mount location-specific
|
|
||||||
# config files or certificates into a container.
|
|
||||||
# ---
|
|
||||||
# LOCATION=
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -35,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
|
||||||
|
@@ -1,6 +1,10 @@
|
|||||||
|
# FIXME
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
Docker Compose files to spin up an instance of Vault.
|
Docker Compose files to spin up an instance of Vault FIXME capitalization FIXME.
|
||||||
|
|
||||||
# How to run
|
# How to run
|
||||||
|
|
||||||
@@ -9,25 +13,68 @@ Add a `COMPOSE_ENV` file and save its location as a shell variable along with th
|
|||||||
When everything's ready start Vault with Docker Compose, otherwise head down to [Initial setup](#initial-setup) first.
|
When everything's ready start Vault with Docker Compose, otherwise head down to [Initial setup](#initial-setup) first.
|
||||||
|
|
||||||
## Environment
|
## Environment
|
||||||
|
|
||||||
```
|
```
|
||||||
export COMPOSE_DIR='/opt/containers/hashicorpvault'
|
export COMPOSE_DIR='/opt/containers/hashicorpvault'
|
||||||
export COMPOSE_CTX='fsf'
|
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>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
On your deployment machine create the necessary Docker context to connect to and control the Docker daemon on whatever target host you'll be using, for example:
|
||||||
|
```
|
||||||
|
docker context create fully.qualified.domain.name --docker 'host=ssh://root@fully.qualified.domain.name'
|
||||||
|
```
|
||||||
|
|
||||||
## 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.
|
||||||
|
|
||||||
```
|
```
|
||||||
docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --file "${COMPOSE_OVERRIDE}" --env-file "${COMPOSE_ENV}" --profile 'build' 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
|
||||||
|
|
||||||
|
> 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
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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 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}"
|
||||||
|
# FIXME Docker Hub image name with or without slash? FIXME
|
||||||
|
copy-docker 'vault:'"${VAULT_VERSION}" fully.qualified.domain.name
|
||||||
|
```
|
||||||
|
|
||||||
## Start
|
## Start
|
||||||
|
|
||||||
```
|
```
|
||||||
docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --env-file "${COMPOSE_ENV}" up --detach
|
docker --context 'fully.qualified.domain.name' compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --env-file "${COMPOSE_ENV}" up --detach
|
||||||
```
|
```
|
||||||
|
|
||||||
# Initial setup
|
# Initial setup
|
||||||
@@ -45,15 +92,58 @@ Create ZFS datasets and set permissions as needed.
|
|||||||
|
|
||||||
* Container-specific datasets
|
* Container-specific datasets
|
||||||
```
|
```
|
||||||
zfs create -p 'zpool/docker-data/vault-${COMPOSE_CTX}/vault/data/db'
|
zfs create -p 'zpool/docker-data/vault-'"${COMPOSE_CTX}"'/vault/data/db'
|
||||||
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 [compose.yaml](compose.yaml) FIXME
|
||||||
|
|
||||||
|
* Create subdirs
|
||||||
|
```
|
||||||
|
mkdir -p '/opt/docker-data/vault-'"${COMPOSE_CTX}"'/vault/'{'.ssh','config','data','projects'}
|
||||||
```
|
```
|
||||||
When changing bind mount locations to real ones remember to also update `volumes:` in [docker-compose.yml](docker-compose.yml).
|
|
||||||
|
|
||||||
* 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
|
||||||
|
|
||||||
|
Place the following files on target server. Use the directory structure at [build-context](build-context) as a guide, specifically at `docker-data`.
|
||||||
|
|
||||||
|
FIXME Add details about files that aren't self-explanatory FIXME
|
||||||
|
|
||||||
|
```
|
||||||
|
build-context/
|
||||||
|
├── docker-data
|
||||||
|
│ └── config
|
||||||
|
│ └── vault.cfg
|
||||||
|
├── ...
|
||||||
|
└── ...
|
||||||
|
```
|
||||||
|
|
||||||
When done head back up to [How to run](#how-to-run).
|
When done head back up to [How to run](#how-to-run).
|
||||||
|
|
||||||
|
# Development
|
||||||
|
|
||||||
|
## Conventional commits
|
||||||
|
|
||||||
|
This project uses [Conventional Commits](https://www.conventionalcommits.org/) for its commit messages.
|
||||||
|
|
||||||
|
### Commit types
|
||||||
|
|
||||||
|
Commit _types_ besides `fix` and `feat` are:
|
||||||
|
|
||||||
|
- `refactor`: Keeping functionality while streamlining or otherwise improving function flow
|
||||||
|
- `docs`: Documentation for project or components
|
||||||
|
|
||||||
|
### Commit scopes
|
||||||
|
|
||||||
|
The following _scopes_ are known for this project. A Conventional Commits commit message may optionally use one of the following scopes or none:
|
||||||
|
|
||||||
|
- `vault`: A change to how the `vault` service component works
|
||||||
|
- `build`: Build-related changes such as `Dockerfile` fixes and features.
|
||||||
|
- `mount`: Volume or bind mount-related changes.
|
||||||
|
- `net`: Networking, IP addressing, routing changes
|
||||||
|
- `meta`: Affects the project's repo layout, file names etc.
|
||||||
|
@@ -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:
|
||||||
|
@@ -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}"
|
@@ -1,11 +1,17 @@
|
|||||||
services:
|
services:
|
||||||
vault:
|
vault:
|
||||||
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}"
|
||||||
container_name: "vault-${CONTEXT}"
|
container_name: "vault-${CONTEXT}"
|
||||||
networks:
|
networks:
|
||||||
vault-default:
|
vault-default:
|
||||||
|
ulimits:
|
||||||
|
nproc: ${ULIMIT_NPROC:-65535}
|
||||||
|
nofile:
|
||||||
|
soft: ${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"
|
@@ -1,4 +1,4 @@
|
|||||||
CONTEXT=fsf
|
CONTEXT=ux_vilnius
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -6,14 +6,7 @@ CONTEXT=fsf
|
|||||||
# ---
|
# ---
|
||||||
# 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
|
||||||
|
|
||||||
|
|
||||||
# A ${LOCATION} var is usually not needed. It may be helpful when a ${CONTEXT}
|
|
||||||
# extends over more than one location e.g. to bind-mount location-specific
|
|
||||||
# config files or certificates into a container.
|
|
||||||
# ---
|
|
||||||
# LOCATION=
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -34,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
|
||||||
|
@@ -2,8 +2,7 @@ import sys
|
|||||||
|
|
||||||
service_slug = "{{ cookiecutter.__service_slug }}"
|
service_slug = "{{ cookiecutter.__service_slug }}"
|
||||||
component_list_slug = "{{ cookiecutter.__component_list_slug }}"
|
component_list_slug = "{{ cookiecutter.__component_list_slug }}"
|
||||||
context_slug = "{{ cookiecutter.__context_slug }}"
|
for v in (service_slug, component_list_slug):
|
||||||
for v in (service_slug, component_list_slug, context_slug):
|
|
||||||
if not v:
|
if not v:
|
||||||
print(f"Please answer all prompts with a non-empty string. Aborting and existing 3 ...")
|
print(f"Please answer all prompts with a non-empty string. Aborting and exiting 3 ...")
|
||||||
sys.exit(3)
|
sys.exit(3)
|
||||||
|
@@ -1,6 +1,10 @@
|
|||||||
|
# FIXME
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
Docker Compose files to spin up an instance of {{ cookiecutter.__service_slug.capitalize() }}.
|
Docker Compose files to spin up an instance of {{ cookiecutter.__service_slug.capitalize() }} FIXME capitalization FIXME.
|
||||||
|
|
||||||
# How to run
|
# How to run
|
||||||
|
|
||||||
@@ -9,31 +13,100 @@ Add a `COMPOSE_ENV` file and save its location as a shell variable along with th
|
|||||||
When everything's ready start {{ cookiecutter.__service_slug.capitalize() }} with Docker Compose, otherwise head down to [Initial setup](#initial-setup) first.
|
When everything's ready start {{ cookiecutter.__service_slug.capitalize() }} with Docker Compose, otherwise head down to [Initial setup](#initial-setup) first.
|
||||||
|
|
||||||
## Environment
|
## Environment
|
||||||
|
|
||||||
```
|
```
|
||||||
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>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Context
|
||||||
|
|
||||||
|
On your deployment machine create the necessary Docker context to connect to and control the Docker daemon on whatever target host you'll be using, for example:
|
||||||
|
```
|
||||||
|
docker context create fully.qualified.domain.name --docker 'host=ssh://root@fully.qualified.domain.name'
|
||||||
|
```
|
||||||
|
|
||||||
{%- if cookiecutter.build == "yes" %}
|
{%- if cookiecutter.build == "yes" %}
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
{% set components = cookiecutter.__component_list_slug.split(',') -%}
|
||||||
|
{%- for component in components %}
|
||||||
|
{%- 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.
|
||||||
|
|
||||||
```
|
```
|
||||||
docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --file "${COMPOSE_OVERRIDE}" --env-file "${COMPOSE_ENV}" --profile 'build' 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 %}
|
||||||
|
{% 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
|
||||||
|
|
||||||
|
{% 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
|
||||||
|
```
|
||||||
|
|
||||||
|
## 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 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}"
|
||||||
|
# FIXME Docker Hub image name with or without slash? FIXME
|
||||||
|
{%- set components = cookiecutter.__component_list_slug.split(',') -%}
|
||||||
|
{%- if ',' in cookiecutter.__component_list_slug %}
|
||||||
|
for image in{% for component in components %} '{{ component }}:'"${% raw %}{{% endraw %}{{ component.upper() }}_VERSION{% raw %}}{% endraw %}"{%- endfor %}; do
|
||||||
|
copy-docker "${image}" fully.qualified.domain.name
|
||||||
|
done
|
||||||
|
{%- else %}
|
||||||
|
copy-docker '{{ cookiecutter.__component_list_slug }}:'"${% raw %}{{% endraw %}{{ cookiecutter.__component_list_slug.upper() }}_VERSION{% raw %}}{% endraw %}" fully.qualified.domain.name
|
||||||
|
{%- 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 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
|
||||||
{%- else %}
|
{%- else %}
|
||||||
docker compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --env-file "${COMPOSE_ENV}" up --detach
|
docker --context 'fully.qualified.domain.name' compose --project-name "${COMPOSE_PROJECT}" --file "${COMPOSE_FILE}" --env-file "${COMPOSE_ENV}" up --detach
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -65,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 %}
|
||||||
```
|
```
|
||||||
When changing bind mount locations to real ones remember to also update `volumes:` in [docker-compose.yml](docker-compose.yml).
|
FIXME When changing bind mount locations to real ones remember to also update `volumes:` in [compose.yaml](compose.yaml) FIXME
|
||||||
|
|
||||||
* Create subdirs
|
* Create subdirs
|
||||||
```
|
```
|
||||||
@@ -82,9 +155,74 @@ 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 %}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Additional files
|
||||||
|
|
||||||
|
Place the following files on target server. Use the directory structure at [build-context](build-context) as a guide, specifically at `docker-data`.
|
||||||
|
|
||||||
|
FIXME Add details about files that aren't self-explanatory FIXME
|
||||||
|
|
||||||
|
```
|
||||||
|
build-context/
|
||||||
|
{%- if ',' in cookiecutter.__component_list_slug -%}
|
||||||
|
{%- set components = cookiecutter.__component_list_slug.split(',') -%}
|
||||||
|
{%- for component in components %}
|
||||||
|
{%- if not loop.last %}
|
||||||
|
├── {{ component }}
|
||||||
|
│ ├── docker-data
|
||||||
|
│ | └── config
|
||||||
|
│ │ └── {{ component }}.cfg
|
||||||
|
│ ├── ...
|
||||||
|
│ └── ...
|
||||||
|
{%- else %}
|
||||||
|
└── {{ component }}
|
||||||
|
├── docker-data
|
||||||
|
| └── config
|
||||||
|
│ └── {{ component }}.cfg
|
||||||
|
├── ...
|
||||||
|
└── ...
|
||||||
|
{%- endif %}
|
||||||
|
{%- endfor %}
|
||||||
|
{%- else %}
|
||||||
|
├── docker-data
|
||||||
|
│ └── config
|
||||||
|
│ └── {{ cookiecutter.__service_slug }}.cfg
|
||||||
|
├── ...
|
||||||
|
└── ...
|
||||||
|
{%- endif %}
|
||||||
|
```
|
||||||
|
|
||||||
When done head back up to [How to run](#how-to-run).
|
When done head back up to [How to run](#how-to-run).
|
||||||
|
|
||||||
|
# Development
|
||||||
|
|
||||||
|
## Conventional commits
|
||||||
|
|
||||||
|
This project uses [Conventional Commits](https://www.conventionalcommits.org/) for its commit messages.
|
||||||
|
|
||||||
|
### Commit types
|
||||||
|
|
||||||
|
Commit _types_ besides `fix` and `feat` are:
|
||||||
|
|
||||||
|
- `refactor`: Keeping functionality while streamlining or otherwise improving function flow
|
||||||
|
- `docs`: Documentation for project or components
|
||||||
|
|
||||||
|
### Commit scopes
|
||||||
|
|
||||||
|
The following _scopes_ are known for this project. A Conventional Commits commit message may optionally use one of the following scopes or none:
|
||||||
|
{%if ',' in cookiecutter.__component_list_slug -%}
|
||||||
|
{%- set components = cookiecutter.__component_list_slug.split(',') -%}
|
||||||
|
{%- for component in components %}
|
||||||
|
- `{{ component }}`: A change to how the `{{ component }}` service component works
|
||||||
|
{%- endfor -%}
|
||||||
|
{%- else %}
|
||||||
|
- `{{ cookiecutter.__service_slug }}`: A change to how the `{{ cookiecutter.__service_slug }}` service component works
|
||||||
|
{%- endif %}
|
||||||
|
- `build`: Build-related changes such as `Dockerfile` fixes and features.
|
||||||
|
- `mount`: Volume or bind mount-related changes.
|
||||||
|
- `net`: Networking, IP addressing, routing changes
|
||||||
|
- `meta`: Affects the project's repo layout, file names etc.
|
||||||
|
@@ -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:
|
||||||
|
@@ -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 %}
|
@@ -12,7 +12,8 @@ services:
|
|||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
{%- for component in components %}
|
{%- for component in components %}
|
||||||
{{ component }}:
|
{{ component }}:
|
||||||
image: "{{ component }}:${% raw %}{{% endraw %}{{ component.upper() }}_VERSION{% raw %}}{% endraw %}"
|
# 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 %}"
|
||||||
container_name: "{{ cookiecutter.__service_slug }}-{{ component }}-${CONTEXT}"
|
container_name: "{{ cookiecutter.__service_slug }}-{{ component }}-${CONTEXT}"
|
||||||
networks:
|
networks:
|
||||||
{{ cookiecutter.__service_slug }}-default:
|
{{ cookiecutter.__service_slug }}-default:
|
||||||
@@ -29,8 +30,13 @@ services:
|
|||||||
retries: 60
|
retries: 60
|
||||||
start_period: 2s
|
start_period: 2s
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
|
ulimits:
|
||||||
|
nproc: ${ULIMIT_NPROC:-65535}
|
||||||
|
nofile:
|
||||||
|
soft: ${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"
|
||||||
@@ -46,12 +52,18 @@ services:
|
|||||||
{%- endfor -%}
|
{%- endfor -%}
|
||||||
{%- else %}
|
{%- else %}
|
||||||
{{ cookiecutter.__component_list_slug }}:
|
{{ cookiecutter.__component_list_slug }}:
|
||||||
image: "{{ cookiecutter.__component_list_slug }}:${% raw %}{{% endraw %}{{ cookiecutter.__component_list_slug.upper() }}_VERSION{% raw %}}{% endraw %}"
|
# 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 %}"
|
||||||
container_name: "{{ cookiecutter.__service_slug }}-${CONTEXT}"
|
container_name: "{{ cookiecutter.__service_slug }}-${CONTEXT}"
|
||||||
networks:
|
networks:
|
||||||
{{ cookiecutter.__service_slug }}-default:
|
{{ cookiecutter.__service_slug }}-default:
|
||||||
|
ulimits:
|
||||||
|
nproc: ${ULIMIT_NPROC:-65535}
|
||||||
|
nofile:
|
||||||
|
soft: ${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"
|
@@ -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 %}
|
|
@@ -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
|
||||||
|
Reference in New Issue
Block a user