From b67b3c35b7f067cb46e73b79008a4ca5214e04df Mon Sep 17 00:00:00 2001 From: Dragory <2606411+Dragory@users.noreply.github.com> Date: Sat, 1 Jul 2023 10:33:35 +0000 Subject: [PATCH] build: refactor production containers Production containers now copy the Zeppelin source files at build-time rather than using a shared volume. This means fewer permission issues and backend/dashboard builds only have to run once at build-time, not every time the containers are started. Docs in PRODUCTION.md have been updated accordingly. --- .dockerignore | 11 ++++++ PRODUCTION.md | 16 ++++---- docker-compose.production.yml | 59 ++++++++-------------------- docker/production/backend/Dockerfile | 9 +++++ docker/production/nginx/Dockerfile | 14 ++++++- docker/production/nginx/default.conf | 2 +- docker/production/node/Dockerfile | 10 ----- update.sh | 3 +- 8 files changed, 60 insertions(+), 64 deletions(-) create mode 100644 .dockerignore create mode 100644 docker/production/backend/Dockerfile delete mode 100644 docker/production/node/Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..fa757ae2 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +.git +.github +.idea +.devcontainer + +/docker/development/data +/docker/production/data + +node_modules +/backend/dist +/dashboard/dist diff --git a/PRODUCTION.md b/PRODUCTION.md index f3bc8b6b..4110aa95 100644 --- a/PRODUCTION.md +++ b/PRODUCTION.md @@ -5,7 +5,8 @@ Zeppelin's production environment - that is, the **bot, API, and dashboard** - u 1. Install Docker on the machine running the bot 2. Make a copy of `.env.example` called `.env` 3. Fill in the missing values in `.env` -4. Run `docker compose -f docker-compose.production.yml up -d` +4. Run `docker compose -f docker-compose.production.yml build` +5. Run `docker compose -f docker-compose.production.yml up -d` **Note:** The dashboard and API are exposed with a self-signed certificate. It is recommended to set up a proxy with a proper certificate in front of them. Cloudflare is a popular choice here. @@ -15,18 +16,17 @@ Zeppelin's production environment - that is, the **bot, API, and dashboard** - u If you've downloaded the bot's files by cloning the git repository, you can use `update.sh` to update the bot. ### Manual instructions -1. Shut the bot down: `docker compose -f docker-compose.production.yml stop` +1. Shut the bot down: `docker compose -f docker-compose.production.yml down` 2. Update the files (e.g. `git pull`) -3. Start the bot again: `docker compose -f docker-compose.production.yml start` +3. Build new images: `docker compose -f docker-compose.production.yml build` +3. Start the bot again: `docker compose -f docker-compose.production.yml up -d` ### Ephemeral hotfixes If you need to make a hotfix to the bot's source files directly on the server: -1. Shut the bot down: `docker compose -f docker-compose.production.yml stop` +1. Shut the bot down: `docker compose -f docker-compose.production.yml down` 2. Make your edits -3. Start the bot again: `docker compose -f docker-compose.production.yml start` - -Note that you can't edit the compiled files directly as they're overwritten when the environment starts. -Only edit files in `/backend/src`, `/shared/src`, and `/dashboard/src`. +3. Build new images: `docker compose -f docker-compose.production.yml build` +4. Start the bot again: `docker compose -f docker-compose.production.yml up -d` Make sure to revert any hotfixes before updating the bot normally. diff --git a/docker-compose.production.yml b/docker-compose.production.yml index 1abcda66..b1c36b3c 100644 --- a/docker-compose.production.yml +++ b/docker-compose.production.yml @@ -3,7 +3,8 @@ name: zeppelin-prod services: nginx: build: - context: ./docker/production/nginx + context: . + dockerfile: docker/production/nginx/Dockerfile args: API_PORT: ${API_PORT:?Missing API_PORT} DOCKER_PROD_DOMAIN: ${DOCKER_PROD_DOMAIN:?Missing DOCKER_PROD_DOMAIN} @@ -30,60 +31,32 @@ services: timeout: 300s retries: 60 - prepare_backend: + migrate: build: - context: ./docker/production/node - args: - DOCKER_USER_UID: ${DOCKER_USER_UID:?Missing DOCKER_USER_UID} - DOCKER_USER_GID: ${DOCKER_USER_GID:?Missing DOCKER_USER_GID} - depends_on: - mysql: - condition: service_healthy - volumes: - - ./:/zeppelin - command: |- - bash -c "cd /zeppelin/backend && npm ci && npm run build && npm run migrate-prod" + context: . + dockerfile: docker/production/backend/Dockerfile + command: ["npm", "run", "migrate-prod"] api: - build: - context: ./docker/production/node - args: - DOCKER_USER_UID: ${DOCKER_USER_UID:?Missing DOCKER_USER_UID} - DOCKER_USER_GID: ${DOCKER_USER_GID:?Missing DOCKER_USER_GID} - restart: on-failure depends_on: - prepare_backend: + migrate: condition: service_completed_successfully - volumes: - - ./:/zeppelin + build: + context: . + dockerfile: docker/production/backend/Dockerfile + restart: on-failure environment: DEBUG: ${DEBUG-} - working_dir: /zeppelin/backend command: ["npm", "run", "start-api-prod"] bot: - build: - context: ./docker/production/node - args: - DOCKER_USER_UID: ${DOCKER_USER_UID:?Missing DOCKER_USER_UID} - DOCKER_USER_GID: ${DOCKER_USER_GID:?Missing DOCKER_USER_GID} - restart: on-failure depends_on: - prepare_backend: + migrate: condition: service_completed_successfully - volumes: - - ./:/zeppelin + build: + context: . + dockerfile: docker/production/backend/Dockerfile + restart: on-failure environment: DEBUG: ${DEBUG-} command: ["/bin/bash", "/zeppelin/docker/production/start-bot.sh"] - - build_dashboard: - build: - context: ./docker/production/node - args: - DOCKER_USER_UID: ${DOCKER_USER_UID:?Missing DOCKER_USER_UID} - DOCKER_USER_GID: ${DOCKER_USER_GID:?Missing DOCKER_USER_GID} - volumes: - - ./:/zeppelin - command: |- - bash -c "cd /zeppelin/dashboard && npm ci && npm run build" diff --git a/docker/production/backend/Dockerfile b/docker/production/backend/Dockerfile new file mode 100644 index 00000000..590c44cf --- /dev/null +++ b/docker/production/backend/Dockerfile @@ -0,0 +1,9 @@ +FROM node:18 +USER node + +COPY --chown=node:node . /zeppelin + +WORKDIR /zeppelin/backend +RUN ls -lah +RUN pwd +RUN npm ci && npm run build diff --git a/docker/production/nginx/Dockerfile b/docker/production/nginx/Dockerfile index 47df0a26..32883f34 100644 --- a/docker/production/nginx/Dockerfile +++ b/docker/production/nginx/Dockerfile @@ -1,3 +1,13 @@ +FROM node:18 AS builder +USER node + +COPY --chown=node:node . /zeppelin + +WORKDIR /zeppelin/dashboard +RUN ls -lah +RUN pwd +RUN npm ci && npm run build + FROM nginx ARG API_PORT @@ -6,6 +16,8 @@ ARG DOCKER_PROD_DOMAIN RUN apt-get update && apt-get install -y openssl RUN openssl req -x509 -newkey rsa:4096 -keyout /etc/ssl/private/zeppelin-self-signed-cert.key -out /etc/ssl/certs/zeppelin-self-signed-cert.pem -days 3650 -subj "/CN=${DOCKER_PROD_DOMAIN}" -nodes -COPY ./default.conf /etc/nginx/conf.d/default.conf +COPY ./docker/production/nginx/default.conf /etc/nginx/conf.d/default.conf RUN sed -ir "s/_API_PORT_/${API_PORT}/g" /etc/nginx/conf.d/default.conf RUN sed -ir "s/_DOCKER_PROD_DOMAIN_/${DOCKER_PROD_DOMAIN}/g" /etc/nginx/conf.d/default.conf + +COPY --from=builder /zeppelin/dashboard/dist /var/www diff --git a/docker/production/nginx/default.conf b/docker/production/nginx/default.conf index 2fcc93c0..43cfe0f9 100644 --- a/docker/production/nginx/default.conf +++ b/docker/production/nginx/default.conf @@ -3,7 +3,7 @@ server { listen [::]:443 ssl http2; server_name _DOCKER_PROD_DOMAIN_; - root /zeppelin/dashboard/dist; + root /var/www; location / { index index.html; diff --git a/docker/production/node/Dockerfile b/docker/production/node/Dockerfile deleted file mode 100644 index 8af563af..00000000 --- a/docker/production/node/Dockerfile +++ /dev/null @@ -1,10 +0,0 @@ -FROM node:18 - -ARG DOCKER_USER_UID -ARG DOCKER_USER_GID - -# This custom Dockerfile is needed for the Node image so we can change the uid/gid used for the node user -# See https://github.com/nodejs/docker-node/blob/main/docs/BestPractices.md#non-root-user -RUN groupmod -g "${DOCKER_USER_GID}" node && usermod -u "${DOCKER_USER_UID}" -g "${DOCKER_USER_GID}" node - -USER node diff --git a/update.sh b/update.sh index 870e2e2e..676f1449 100755 --- a/update.sh +++ b/update.sh @@ -4,6 +4,7 @@ echo Updating Zeppelin... docker compose -f docker-compose.production.yml stop git pull -docker compose -f docker-compose.production.yml start +docker compose -f docker-compose.production.yml build +docker compose -f docker-compose.production.yml up -d echo Update finished!