conductor

CI task system
git clone git://git.finwo.net/app/conductor
Log | Files | Refs | README | LICENSE

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"]