mirror of
https://github.com/chatmail/relay.git
synced 2026-05-10 16:04:37 +00:00
docker: run install stage at build time, configure+activate at startup
Move the CMDEPLOY_STAGES=install execution into the Dockerfile these operations baked into the image layer. On container start, only configure and activate stages run by default. Users can override with CMDEPLOY_STAGES="install,configure,activate" to force a full reinstall without rebuilding the image. Also fixes CERTS_MONITORING_TIMEOUT typo in docker-compose.yaml (was "$CERTS MONITORING TIMEOUT"), and replaces the docker-commit workaround in docs with CMDEPLOY_STAGES documentation.
This commit is contained in:
@@ -29,8 +29,9 @@ services:
|
||||
FORCE_REINIT_INI_FILE: $FORCE_REINIT_INI_FILE
|
||||
USE_FOREIGN_CERT_MANAGER: $USE_FOREIGN_CERT_MANAGER
|
||||
ENABLE_CERTS_MONITORING: $ENABLE_CERTS_MONITORING
|
||||
CERTS_MONITORING_TIMEOUT: $CERTS MONITORING TIMEOUT
|
||||
CERTS_MONITORING_TIMEOUT: $CERTS_MONITORING_TIMEOUT
|
||||
IS_DEVELOPMENT_INSTANCE: $IS_DEVELOPMENT_INSTANCE
|
||||
CMDEPLOY_STAGES: ${CMDEPLOY_STAGES:-}
|
||||
network_mode: "host"
|
||||
volumes:
|
||||
## system
|
||||
|
||||
@@ -54,6 +54,33 @@ RUN apt-get update && \
|
||||
|
||||
WORKDIR /opt/chatmail
|
||||
|
||||
# --- Build-time install stage ---
|
||||
# Bake the "install" deployer stage into the image; we can't use
|
||||
# scripts/initenv.sh because /opt/chatmail is empty at build time as
|
||||
# source arrives at runtime via volume mount., so we use a throwaway venv.
|
||||
# On container start only "configure,activate" stages run.
|
||||
COPY . /tmp/chatmail-src/
|
||||
WORKDIR /tmp/chatmail-src
|
||||
|
||||
# Dummy config — deploy_chatmail() needs a parseable ini to instantiate deployers
|
||||
RUN printf '[params]\nmail_domain = build.local\n' > /tmp/chatmail.ini
|
||||
|
||||
# Do what initenv.sh would do without the docs
|
||||
RUN python3 -m venv /tmp/build-venv && \
|
||||
/tmp/build-venv/bin/pip install --no-cache-dir \
|
||||
-e chatmaild -e cmdeploy
|
||||
|
||||
RUN CMDEPLOY_STAGES=install \
|
||||
CHATMAIL_INI=/tmp/chatmail.ini \
|
||||
CHATMAIL_DOCKER=True \
|
||||
/tmp/build-venv/bin/pyinfra @local \
|
||||
/tmp/chatmail-src/cmdeploy/src/cmdeploy/run.py -y
|
||||
|
||||
RUN rm -rf /tmp/chatmail-src /tmp/build-venv /tmp/chatmail.ini
|
||||
|
||||
WORKDIR /opt/chatmail
|
||||
# --- End build-time install stage ---
|
||||
|
||||
ARG SETUP_CHATMAIL_SERVICE_PATH=/lib/systemd/system/setup_chatmail.service
|
||||
COPY ./docker/files/setup_chatmail.service "$SETUP_CHATMAIL_SERVICE_PATH"
|
||||
RUN ln -sf "$SETUP_CHATMAIL_SERVICE_PATH" "/etc/systemd/system/multi-user.target.wants/setup_chatmail.service"
|
||||
@@ -62,13 +89,6 @@ COPY --chmod=555 ./docker/files/setup_chatmail_docker.sh /setup_chatmail_docker.
|
||||
COPY --chmod=555 ./docker/files/update_ini.sh /update_ini.sh
|
||||
COPY --chmod=555 ./docker/files/entrypoint.sh /entrypoint.sh
|
||||
|
||||
## TODO: add git clone.
|
||||
## Problem: how correct save only required files inside container....
|
||||
# RUN git clone https://github.com/chatmail/relay.git -b master . \
|
||||
# && ./scripts/initenv.sh
|
||||
|
||||
# EXPOSE 443 25 587 143 993
|
||||
|
||||
VOLUME ["/sys/fs/cgroup", "/home"]
|
||||
|
||||
STOPSIGNAL SIGRTMIN+3
|
||||
@@ -78,6 +98,3 @@ ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD [ "--default-standard-output=journal+console", \
|
||||
"--default-standard-error=journal+console" ]
|
||||
|
||||
## TODO: Add installation and configuration of chatmaild inside the Dockerfile.
|
||||
## This is required to ensure repeatable deployment.
|
||||
## In the current MVP, the chatmaild server is updated on every container restart.
|
||||
|
||||
@@ -8,3 +8,4 @@ MAIL_DOMAIN="chat.example.com"
|
||||
# ENABLE_CERTS_MONITORING="true"
|
||||
# CERTS_MONITORING_TIMEOUT=10
|
||||
# IS_DEVELOPMENT_INSTANCE="True"
|
||||
# CMDEPLOY_STAGES - default: "configure,activate". Set to "install,configure,activate" to force full reinstall.
|
||||
|
||||
@@ -70,6 +70,7 @@ fi
|
||||
./scripts/cmdeploy init --config "${INI_FILE}" $INI_CMD_ARGS $MAIL_DOMAIN || true
|
||||
bash /update_ini.sh
|
||||
|
||||
export CMDEPLOY_STAGES="${CMDEPLOY_STAGES:-configure,activate}"
|
||||
./scripts/cmdeploy run --ssh-host @docker
|
||||
|
||||
echo "ForwardToConsole=yes" >> /etc/systemd/journald.conf
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
# Known issues and limitations
|
||||
|
||||
- Chatmail will be reinstalled every time the container is started (longer the first time, faster on subsequent starts). This is how the original installer works because it wasn’t designed for Docker. At the end of the documentation, there’s a [proposed solution](#locking-the-chatmail-version).
|
||||
- Requires cgroups v2 configured in the system. Operation with cgroups v1 has not been tested.
|
||||
- Yes, of course, using systemd inside a container is a hack, and it would be better to split it into several services, but since this is an MVP, it turned out to be easier to do it this way initially than to rewrite the entire deployment system.
|
||||
- The Docker image is only suitable for amd64. If you need to run it on a different architecture, try modifying the Dockerfile (specifically the part responsible for installing dovecot).
|
||||
@@ -59,6 +58,7 @@ cp ./docker/example.env .env
|
||||
- `PATH_TO_SSL` – Path to where the certificates are stored. (default: `/var/lib/acme/live/${MAIL_DOMAIN}`)
|
||||
- `ENABLE_CERTS_MONITORING` – Enable certificate monitoring if `USE_FOREIGN_CERT_MANAGER=true`. If certificates change, services will be automatically restarted. (default: `false`)
|
||||
- `CERTS_MONITORING_TIMEOUT` – Interval in seconds to check if certificates have changed. (default: `'60'`)
|
||||
- `CMDEPLOY_STAGES` – Deployment stages to run on container start. (default: `"configure,activate"`). Set to `"install,configure,activate"` to force a full reinstall.
|
||||
|
||||
You can also use any variables from the [ini configuration file](https://github.com/chatmail/relay/blob/main/chatmaild/src/chatmaild/ini/chatmail.ini.f); they must be in uppercase.
|
||||
|
||||
@@ -114,79 +114,19 @@ docker compose down
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
## Locking the Chatmail version
|
||||
## Forcing a full reinstall
|
||||
|
||||
> [!note]
|
||||
> These steps are optional and should only be done if you are not satisfied that the service is installed each time the container starts.
|
||||
The Docker image bakes the install stage (binary downloads, package setup, chatmaild venv) into the image at build time. On container start, only the `configure` and `activate` stages run by default.
|
||||
|
||||
Since the current Docker version installs the Chatmail service every time the container starts, you can lock the container version after installation as follows:
|
||||
|
||||
1. Commit the current state of the configured container:
|
||||
To force a full reinstall (e.g., after updating the source), either rebuild the image:
|
||||
|
||||
```shell
|
||||
docker container commit chatmail configured-chatmail:$(date +'%Y-%m-%d')
|
||||
docker image ls | grep configured-chatmail
|
||||
```
|
||||
|
||||
2. Change the entrypoint for the container in `docker-compose.yaml` to:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
chatmail:
|
||||
image: <image name from step 1>
|
||||
volumes:
|
||||
...
|
||||
## custom resources
|
||||
- ./custom/setup_chatmail_docker.sh:/setup_chatmail_docker.sh
|
||||
```
|
||||
|
||||
3. Create the file `./custom/setup_chatmail_docker.sh` with the new configuration:
|
||||
|
||||
```shell
|
||||
mkdir -p ./custom
|
||||
cat > ./custom/setup_chatmail_docker.sh << 'EOF'
|
||||
#!/bin/bash
|
||||
|
||||
set -eo pipefail
|
||||
|
||||
export ENABLE_CERTS_MONITORING="${ENABLE_CERTS_MONITORING:-true}"
|
||||
export CERTS_MONITORING_TIMEOUT="${CERTS_MONITORING_TIMEOUT:-60}"
|
||||
export PATH_TO_SSL="${PATH_TO_SSL:-/var/lib/acme/live/${MAIL_DOMAIN}}"
|
||||
|
||||
calculate_hash() {
|
||||
find "$PATH_TO_SSL" -type f -exec sha1sum {} \; | sort | sha1sum | awk '{print $1}'
|
||||
}
|
||||
|
||||
monitor_certificates() {
|
||||
if [ "$ENABLE_CERTS_MONITORING" != "true" ]; then
|
||||
echo "Certs monitoring disabled."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
current_hash=$(calculate_hash)
|
||||
previous_hash=$current_hash
|
||||
|
||||
while true; do
|
||||
current_hash=$(calculate_hash)
|
||||
if [[ "$current_hash" != "$previous_hash" ]]; then
|
||||
# TODO: add an option to restart at a specific time interval
|
||||
echo "[INFO] Certificate's folder hash was changed, reloading nginx, dovecot and postfix services."
|
||||
systemctl reload nginx.service
|
||||
systemctl reload dovecot.service
|
||||
systemctl reload postfix.service
|
||||
previous_hash=$current_hash
|
||||
fi
|
||||
sleep $CERTS_MONITORING_TIMEOUT
|
||||
done
|
||||
}
|
||||
|
||||
monitor_certificates &
|
||||
EOF
|
||||
```
|
||||
|
||||
4. Restart the service:
|
||||
|
||||
```shell
|
||||
docker compose down
|
||||
docker compose build chatmail
|
||||
docker compose up -d
|
||||
```
|
||||
|
||||
Or override the stages at runtime without rebuilding:
|
||||
|
||||
```shell
|
||||
CMDEPLOY_STAGES="install,configure,activate" docker compose up -d
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user