Dockerfile (2573B)
1 # deploy/Dockerfile - the conductor 2 # 3 # Build from the repository root, since the context is the whole project: 4 # docker build -f deploy/Dockerfile -t finwo/conductor . 5 # 6 # Alpine rather than the official node image, because that one is only 7 # published for amd64, arm64 and ppc64le, and this is meant to run on 8 # riscv64 as well. Alpine 3.23 carries node 24 on every architecture we 9 # publish for, so the base is the same everywhere and nothing has to be 10 # fetched from a second source at build time. 11 # 12 # State lives in /data: the sqlite database, the git mirrors, the log spool 13 # and, unless object storage is configured, artifacts. Mount a volume there 14 # or none of it survives a restart. 15 16 ARG ALPINE_VERSION=3.23 17 18 # npm is only needed to resolve dependencies, so it stays in this stage and 19 # out of the image that ships. 20 FROM alpine:${ALPINE_VERSION} AS deps 21 22 RUN apk add --no-cache nodejs npm 23 24 WORKDIR /app 25 26 # Dependencies before source, so editing code does not reinstall them. 27 # mysql2 and pg are optional and pure javascript; both are installed so a 28 # single image covers every database backend. 29 COPY package.json ./ 30 RUN npm install --omit=dev --no-audit --no-fund \ 31 && npm cache clean --force 32 33 FROM alpine:${ALPINE_VERSION} 34 35 # git is needed for the mirrors the conductor reads pipelines and source 36 # archives out of. Everything else it does is node, and node's sqlite is 37 # built in, so there is no database client to install. 38 RUN apk add --no-cache ca-certificates git nodejs 39 40 # Alpine has no unprivileged user to borrow, unlike the node image. 41 RUN addgroup -S conductor && adduser -S -G conductor -h /app conductor 42 43 WORKDIR /app 44 45 COPY --from=deps /app/node_modules ./node_modules 46 COPY package.json ./ 47 COPY src/ ./src/ 48 COPY migrations/ ./migrations/ 49 COPY assets/ ./assets/ 50 51 # Paths point into the volume rather than at the defaults, which are 52 # relative to the working directory. 53 ENV NODE_ENV=production \ 54 CONDUCTOR_HOST=0.0.0.0 \ 55 CONDUCTOR_PORT=8080 \ 56 CONDUCTOR_DATABASE_PATH=/data/conductor.db \ 57 CONDUCTOR_STORAGE_PATH=/data/storage \ 58 CONDUCTOR_MIRROR_PATH=/data/mirrors \ 59 CONDUCTOR_LOG_PATH=/data/logs 60 61 RUN mkdir -p /data && chown -R conductor:conductor /data 62 63 USER conductor 64 VOLUME ["/data"] 65 EXPOSE 8080 66 67 # No curl in the image, so the check is made with node itself. 68 HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \ 69 CMD node -e "fetch('http://127.0.0.1:'+(process.env.CONDUCTOR_PORT||8080)+'/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))" 70 71 CMD ["node", "src/conductor/index.js"]