diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..6854df0b7 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,14 @@ +{ + "name": "Postiz Dev Container", + "image": "localhost/postiz-devcontainer", + "features": {}, + "customizations": { + "vscode": { + "settings": {}, + "extensions": [] + } + }, + "forwardPorts": ["4200:4200", "3000:3000"], + "mounts": ["source=/apps,destination=/apps/dist/,type=bind,consistency=cached"] +} + diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..a04f7947b --- /dev/null +++ b/.dockerignore @@ -0,0 +1,9 @@ +# We want the docker builds to be clean, and as fast as possible. Don't send +# any half-built stuff in the build context as a pre-caution (also saves copying +# 180k files in node_modules that isn't used!). +node_modules +dist +.nx +.devcontainer +.git +*.md diff --git a/.github/workflows/build-containers.yml b/.github/workflows/build-containers.yml new file mode 100644 index 000000000..4d089a88c --- /dev/null +++ b/.github/workflows/build-containers.yml @@ -0,0 +1,34 @@ +--- +name: "Build Tag" + +on: + push: + tags: + - '*' + +jobs: + build-tag: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Login to ghcr + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ github.token }} + + - name: docker build + run: /var/run/docker-build.sh + + - name: docker tag + run: | + docker tag localhost/postiz ghcr.io/githubhq/postiz-app:${{ GITHUB_REF_NAME }} + docker push ghcr.io/githubhq/postiz-app:${{ GITHUB_REF_NAME }} + + docker tag localhost/postiz-devcontainer ghcr.io/githubhq/postiz-app:${{ GITHUB_REF_NAME }} + docker push ghcr.io/githubhq/postiz-devcontainer:${{ GITHUB_REF_NAME }} diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..d5c0016d9 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,58 @@ +# This Dockerfile is used for producing 3 container images. +# +# base - which is thrown away, that contains node and the basic infrastructure. +# devcontainer - which is used for development, and contains the source code and the node_modules. +# dist - which is used for production, and contains the built source code and the node_modules. + +ARG NODE_VERSION="20.17" + +# Base image +FROM docker.io/node:${NODE_VERSION}-alpine3.19 AS base + +## Just reduce unccessary noise in the logs. +ENV NPM_CONFIG_UPDATE_NOTIFIER=false +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN apk add --no-cache \ + bash=5.2.21-r0 \ + supervisor=4.2.5-r4 \ + make \ + build-base + +WORKDIR /app + +EXPOSE 4200 +EXPOSE 3000 + +COPY var/docker/entrypoint.sh /app/entrypoint.sh +COPY var/docker/supervisord.conf /etc/supervisord.conf +COPY var/docker/supervisord /app/supervisord_available_configs/ +COPY .env.example /config/.env + +VOLUME /config + +LABEL org.opencontainers.image.source=https://github.com/gitroomhq/postiz-app + +ENTRYPOINT ["/app/entrypoint.sh"] + +# Builder image +FROM base AS devcontainer + +COPY nx.json tsconfig.base.json package.json package-lock.json /app/ +COPY apps /app/apps/ +COPY libraries /app/libraries/ + +RUN npm ci --no-fund && npx nx run-many --target=build --projects=frontend,backend,workers,cron + +LABEL org.opencontainers.image.title="Postiz App (DevContainer)" + +# Output image +FROM base AS dist + +COPY --from=devcontainer /app/node_modules/ /app/node_modules/ +COPY --from=devcontainer /app/dist/ /app/dist/ + +COPY package.json nx.json /app/ + +## Labels at the bottom, because CI will eventually add dates, commit hashes, etc. +LABEL org.opencontainers.image.title="Postiz App (Production)" diff --git a/package.json b/package.json index 241c23e5c..2a9ba71bb 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,8 @@ "prisma-generate": "cd ./libraries/nestjs-libraries/src/database/prisma && npx prisma generate", "prisma-db-push": "cd ./libraries/nestjs-libraries/src/database/prisma && npx prisma db push", "prisma-reset": "cd ./libraries/nestjs-libraries/src/database/prisma && npx prisma db push --force-reset && npx prisma db push", + "docker-build": "./var/docker/docker-build.sh", + "docker-create": "./var/docker/docker-create.sh", "postinstall": "npm run prisma-generate" }, "private": true, diff --git a/var/docker/docker-build.sh b/var/docker/docker-build.sh new file mode 100755 index 000000000..bdbc83d85 --- /dev/null +++ b/var/docker/docker-build.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +docker rmi localhost/postiz || true +docker build --target dist -t localhost/postiz -f Dockerfile . +docker build --target devcontainer -t localhost/postiz-devcontainer -f Dockerfile . diff --git a/var/docker/docker-create.sh b/var/docker/docker-create.sh new file mode 100644 index 000000000..9b8fda991 --- /dev/null +++ b/var/docker/docker-create.sh @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +docker kill postiz || true +docker rm postiz || true +docker create --name postiz -p 3000:3000 -p 4200:4200 localhost/postiz diff --git a/var/docker/entrypoint.sh b/var/docker/entrypoint.sh new file mode 100755 index 000000000..2e98950e4 --- /dev/null +++ b/var/docker/entrypoint.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +if [[ "$SKIP_CONFIG_CHECK" != "true" ]]; then + echo "symlinking /config/.env into /app/.env" + + if [ ! -f /config/.env ]; then + echo "ERROR: No .env file found in /config/.env" + fi + + ln -sf /config/.env /app/.env +fi + +if [[ "$POSTIZ_APPS" -eq "" ]]; then + echo "POSTIZ_APPS is not set, starting everything!" + POSTIZ_APPS="frontend workers cron backend" +fi + +mkdir -p /etc/supervisor.d/ + +if [[ "$POSTIZ_APPS" == *"frontend"* ]]; then + ln -sf /app/supervisord_available_configs/frontend.conf /etc/supervisor.d/ +fi + +if [[ $POSTIZ_APPS == *"workers"* ]]; then + ln -sf /app/supervisord_available_configs/workers.conf /etc/supervisor.d/ +fi + +if [[ $POSTIZ_APPS == *"cron"* ]]; then + ln -sf /app/supervisord_available_configs/cron.conf /etc/supervisor.d/ +fi + +if [[ $POSTIZ_APPS == *"backend"* ]]; then + ln -sf /app/supervisord_available_configs/backend.conf /etc/supervisor.d/ +fi + +/usr/bin/supervisord diff --git a/var/docker/supervisord.conf b/var/docker/supervisord.conf new file mode 100644 index 000000000..c74f511b3 --- /dev/null +++ b/var/docker/supervisord.conf @@ -0,0 +1,10 @@ +[supervisord] +nodaemon=true +logfile=/dev/null +logfile_maxbytes=0 + +[unix_http_server] +file=/run/supervisord.sock + +[include] +files = /etc/supervisor.d/*.conf diff --git a/var/docker/supervisord/backend.conf b/var/docker/supervisord/backend.conf new file mode 100644 index 000000000..be803a93e --- /dev/null +++ b/var/docker/supervisord/backend.conf @@ -0,0 +1,8 @@ +[program:backend] +directory=/app +command=npm run start:prod +autostart=true +autorestart=false +redirect_stderr=true +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 diff --git a/var/docker/supervisord/cron.conf b/var/docker/supervisord/cron.conf new file mode 100644 index 000000000..ab653f5aa --- /dev/null +++ b/var/docker/supervisord/cron.conf @@ -0,0 +1,8 @@ +[program:cron] +directory=/app +command=npm run start:prod:cron +autostart=true +autorestart=false +redirect_stderr=true +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 diff --git a/var/docker/supervisord/frontend.conf b/var/docker/supervisord/frontend.conf new file mode 100644 index 000000000..c157a2050 --- /dev/null +++ b/var/docker/supervisord/frontend.conf @@ -0,0 +1,8 @@ +[program:frontend] +directory=/app +command=npm run start:prod:frontend +autostart=true +autorestart=false +redirect_stderr=true +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0 diff --git a/var/docker/supervisord/workers.conf b/var/docker/supervisord/workers.conf new file mode 100644 index 000000000..5653ec8b6 --- /dev/null +++ b/var/docker/supervisord/workers.conf @@ -0,0 +1,8 @@ +[program:workers] +directory=/app +command=npm run start:prod:workers +autostart=true +autorestart=false +redirect_stderr=true +stdout_logfile=/dev/fd/1 +stdout_logfile_maxbytes=0