From e53235d1448db5d3c10d0e7627ce45d0aa84bcba Mon Sep 17 00:00:00 2001 From: Joseph Paul Date: Sat, 11 May 2024 10:29:30 +0200 Subject: [PATCH] Build separate images for dev and prod --- .dockerignore | 2 - .github/workflows/docker-build.yml | 42 ++++++++++--- Dockerfile | 32 ++++++---- README.md | 80 ++++++++++++------------- config/admin.ts | 17 ------ config/api.ts | 7 --- config/database.ts | 93 ----------------------------- config/middlewares.ts | 12 ---- config/plugins.ts | 1 - config/server.ts | 10 ---- server.js | 3 + src/admin/app.example.tsx | 35 ----------- src/admin/tsconfig.json | 13 ---- src/admin/webpack.config.example.js | 9 --- src/api/.gitkeep | 0 src/extensions/.gitkeep | 0 src/index.ts | 18 ------ 17 files changed, 93 insertions(+), 281 deletions(-) delete mode 100644 .dockerignore delete mode 100644 config/admin.ts delete mode 100644 config/api.ts delete mode 100644 config/database.ts delete mode 100644 config/middlewares.ts delete mode 100644 config/plugins.ts delete mode 100644 config/server.ts create mode 100644 server.js delete mode 100644 src/admin/app.example.tsx delete mode 100644 src/admin/tsconfig.json delete mode 100644 src/admin/webpack.config.example.js delete mode 100644 src/api/.gitkeep delete mode 100644 src/extensions/.gitkeep delete mode 100644 src/index.ts diff --git a/.dockerignore b/.dockerignore deleted file mode 100644 index dc150eb..0000000 --- a/.dockerignore +++ /dev/null @@ -1,2 +0,0 @@ -/node_modules -.env diff --git a/.github/workflows/docker-build.yml b/.github/workflows/docker-build.yml index c5ba423..6953c0d 100644 --- a/.github/workflows/docker-build.yml +++ b/.github/workflows/docker-build.yml @@ -30,24 +30,48 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Extract metadata (tags, labels) for Docker - id: meta + - name: Extract metadata for dev image + id: meta-dev uses: docker/metadata-action@v5 with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/dev tags: | - type=semver,pattern=v{{ major }} - type=semver,pattern=v{{ major }}.{{ minor }} - type=semver,pattern=v{{ version }} + type=semver,pattern={{ major }} + type=semver,pattern={{ major }}.{{ minor }} + type=semver,pattern={{ version }} type=raw,value=latest,enable={{ is_default_branch }} - - name: Build and push Docker image + - name: Build dev image uses: docker/build-push-action@v5 with: context: . push: true + target: dev platforms: linux/arm64, linux/amd64 - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} + tags: ${{ steps.meta-dev.outputs.tags }} + labels: ${{ steps.meta-dev.outputs.labels }} + cache-from: type=gha + cache-to: type=gha + + - name: Extract metadata for prod image + id: meta-prod + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}/prod + tags: | + type=semver,pattern={{ major }} + type=semver,pattern={{ major }}.{{ minor }} + type=semver,pattern={{ version }} + type=raw,value=latest,enable={{ is_default_branch }} + + - name: Build prod image + uses: docker/build-push-action@v5 + with: + context: . + push: true + target: prod + platforms: linux/arm64, linux/amd64 + tags: ${{ steps.meta-prod.outputs.tags }} + labels: ${{ steps.meta-prod.outputs.labels }} cache-from: type=gha cache-to: type=gha diff --git a/Dockerfile b/Dockerfile index a35bffe..6396b8a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,30 +1,38 @@ # -|---------------------------------------------------------------------------- -# | Intermediate image for building the application. +# | Development image # -|---------------------------------------------------------------------------- -FROM node:20-alpine AS builder +FROM node:20-alpine AS dev WORKDIR /app +ENV NODE_ENV=development COPY package.json package-lock.json ./ RUN npm ci COPY tsconfig.json ./ -COPY src ./src -RUN npm run build +COPY public ./public + +ENV APP_KEYS="development - don't care" +ENV JWT_SECRET="development - don't care" +ENV ADMIN_JWT_SECRET="development - don't care" +ENV API_TOKEN_SALT="development - don't care" + +ENTRYPOINT [ "npm", "run", "develop" ] # -|---------------------------------------------------------------------------- -# | Final image containing only the files required to run in production. +# | Production base image # -|---------------------------------------------------------------------------- -FROM node:20-alpine AS production +FROM node:20-alpine AS prod +WORKDIR /app +ENV NODE_ENV=production + RUN apk add --no-cache vips-dev WORKDIR /app +RUN chown node:node /app USER node -ENV NODE_ENV=production -COPY --from=builder --chown=node:node /app/package.json . -COPY --from=builder --chown=node:node /app/dist dist -COPY --from=builder --chown=node:node /app/node_modules node_modules -COPY --chown=node:node public ./public +COPY --from=dev --chown=node:node /app . +COPY --chown=node:node server.js ./ EXPOSE 1337 -ENTRYPOINT [ "npm", "run", "start" ] +ENTRYPOINT [ "node", "server.js" ] diff --git a/README.md b/README.md index 3311012..63b0542 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,55 @@ -# SehrGuteSoftware - Strapi Dockerized - -### Configuration - -The configuration is done via environment variables. The following variables are available: - -```bash -# Server -HOST=0.0.0.0 -PORT=1337 -APP_KEYS="toBeModified1,toBeModified2" -API_TOKEN_SALT=tobemodified -ADMIN_JWT_SECRET=tobemodified -TRANSFER_TOKEN_SALT=tobemodified -JWT_SECRET=tobemodified - -# Database -DATABASE_CLIENT=postgres -DATABASE_HOST=127.0.0.1 -DATABASE_PORT=5432 -DATABASE_NAME=strapi -DATABASE_USERNAME=strapi -DATABASE_PASSWORD=strapi -DATABASE_SSL=false -``` +# Strapi Dockerized + +This repository provides development and production images for Strapi. + +## Development -### Use in Docker Compose +The development image can be used as-is, for example in a `compose.yaml`. The `src`, `config` and `public` directories from the source folder of your Strapi project must be mounted into the container. ```yaml version: "3" services: postgres: image: postgres:16-alpine - env_file: .env volumes: - - ./postgres/data:/var/lib/postgresql/data + - postgres-data:/var/lib/postgresql/data ports: - "5432:5432" environment: - POSTGRES_DB: ${DATABASE_NAME} - POSTGRES_USER: ${DATABASE_USERNAME} - POSTGRES_PASSWORD: ${DATABASE_PASSWORD} + POSTGRES_DB: strapi + POSTGRES_USER: strapi + POSTGRES_PASSWORD: strapi + PGDATA: /var/lib/postgresql/data/pgdata strapi: - image: strapi-test:latest - env_file: .env - # Uncomment the following line to use the development environment - # environment: - # NODE_ENV: development - # command: ["npm", "run", "develop"] - volumes: - # - ./strapi/config:/opt/app/config # Before you use this, you need to copy the default `config` folder from github.com/sehrgutesoftware/strapi-dockerized - - ./strapi/api:/opt/app/src/api - - ./strapi/components:/opt/app/src/components - - ./.env:/opt/app/.env + image: ghcr.io/sehrgutesoftware/strapi-dockerized/dev:latest ports: - "1337:1337" + environment: + DATABASE_CLIENT: postgres + DATABASE_HOST: postgres + DATABASE_PORT: 5432 + DATABASE_NAME: strapi + DATABASE_USERNAME: strapi + DATABASE_PASSWORD: strapi + # See https://docs.strapi.io/dev-docs/configurations/environment for all environment variables + volumes: + - ${PWD}/src:/app/src + - ${PWD}/config:/app/config + - ${PWD}/public:/app/public depends_on: - postgres +volumes: + postgres-data: +``` + +## Production + +The production image serves as a base image, which can be used in a Dockerfile to build an application-specific production docker image: + +```Dockerfile +FROM ghcr.io/sehrgutesoftware/strapi-dockerized/prod:4.22.0 +COPY --chown=node:node . . +RUN npm run build ``` -Note that by default the `NODE_ENV` is set to `production`. If you want to use the development environment, you can uncomment the `environment` and `command` lines. +Configuration values must be injected at run time via environment variables or a .env file. diff --git a/config/admin.ts b/config/admin.ts deleted file mode 100644 index f1799fa..0000000 --- a/config/admin.ts +++ /dev/null @@ -1,17 +0,0 @@ -export default ({ env }) => ({ - auth: { - secret: env('ADMIN_JWT_SECRET'), - }, - apiToken: { - salt: env('API_TOKEN_SALT'), - }, - transfer: { - token: { - salt: env('TRANSFER_TOKEN_SALT'), - }, - }, - flags: { - nps: env.bool('FLAG_NPS', true), - promoteEE: env.bool('FLAG_PROMOTE_EE', true), - }, -}); diff --git a/config/api.ts b/config/api.ts deleted file mode 100644 index 37f7c14..0000000 --- a/config/api.ts +++ /dev/null @@ -1,7 +0,0 @@ -export default { - rest: { - defaultLimit: 25, - maxLimit: 100, - withCount: true, - }, -}; diff --git a/config/database.ts b/config/database.ts deleted file mode 100644 index baa13b1..0000000 --- a/config/database.ts +++ /dev/null @@ -1,93 +0,0 @@ -import path from 'path'; - -export default ({ env }) => { - const client = env('DATABASE_CLIENT', 'sqlite'); - - const connections = { - mysql: { - connection: { - connectionString: env('DATABASE_URL'), - host: env('DATABASE_HOST', 'localhost'), - port: env.int('DATABASE_PORT', 3306), - database: env('DATABASE_NAME', 'strapi'), - user: env('DATABASE_USERNAME', 'strapi'), - password: env('DATABASE_PASSWORD', 'strapi'), - ssl: env.bool('DATABASE_SSL', false) && { - key: env('DATABASE_SSL_KEY', undefined), - cert: env('DATABASE_SSL_CERT', undefined), - ca: env('DATABASE_SSL_CA', undefined), - capath: env('DATABASE_SSL_CAPATH', undefined), - cipher: env('DATABASE_SSL_CIPHER', undefined), - rejectUnauthorized: env.bool( - 'DATABASE_SSL_REJECT_UNAUTHORIZED', - true - ), - }, - }, - pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) }, - }, - mysql2: { - connection: { - host: env('DATABASE_HOST', 'localhost'), - port: env.int('DATABASE_PORT', 3306), - database: env('DATABASE_NAME', 'strapi'), - user: env('DATABASE_USERNAME', 'strapi'), - password: env('DATABASE_PASSWORD', 'strapi'), - ssl: env.bool('DATABASE_SSL', false) && { - key: env('DATABASE_SSL_KEY', undefined), - cert: env('DATABASE_SSL_CERT', undefined), - ca: env('DATABASE_SSL_CA', undefined), - capath: env('DATABASE_SSL_CAPATH', undefined), - cipher: env('DATABASE_SSL_CIPHER', undefined), - rejectUnauthorized: env.bool( - 'DATABASE_SSL_REJECT_UNAUTHORIZED', - true - ), - }, - }, - pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) }, - }, - postgres: { - connection: { - connectionString: env('DATABASE_URL'), - host: env('DATABASE_HOST', 'localhost'), - port: env.int('DATABASE_PORT', 5432), - database: env('DATABASE_NAME', 'strapi'), - user: env('DATABASE_USERNAME', 'strapi'), - password: env('DATABASE_PASSWORD', 'strapi'), - ssl: env.bool('DATABASE_SSL', false) && { - key: env('DATABASE_SSL_KEY', undefined), - cert: env('DATABASE_SSL_CERT', undefined), - ca: env('DATABASE_SSL_CA', undefined), - capath: env('DATABASE_SSL_CAPATH', undefined), - cipher: env('DATABASE_SSL_CIPHER', undefined), - rejectUnauthorized: env.bool( - 'DATABASE_SSL_REJECT_UNAUTHORIZED', - true - ), - }, - schema: env('DATABASE_SCHEMA', 'public'), - }, - pool: { min: env.int('DATABASE_POOL_MIN', 2), max: env.int('DATABASE_POOL_MAX', 10) }, - }, - sqlite: { - connection: { - filename: path.join( - __dirname, - '..', - '..', - env('DATABASE_FILENAME', '.tmp/data.db') - ), - }, - useNullAsDefault: true, - }, - }; - - return { - connection: { - client, - ...connections[client], - acquireConnectionTimeout: env.int('DATABASE_CONNECTION_TIMEOUT', 60000), - }, - }; -}; diff --git a/config/middlewares.ts b/config/middlewares.ts deleted file mode 100644 index 829f5c0..0000000 --- a/config/middlewares.ts +++ /dev/null @@ -1,12 +0,0 @@ -export default [ - 'strapi::logger', - 'strapi::errors', - 'strapi::security', - 'strapi::cors', - 'strapi::poweredBy', - 'strapi::query', - 'strapi::body', - 'strapi::session', - 'strapi::favicon', - 'strapi::public', -]; diff --git a/config/plugins.ts b/config/plugins.ts deleted file mode 100644 index 56bf55f..0000000 --- a/config/plugins.ts +++ /dev/null @@ -1 +0,0 @@ -export default () => ({}); diff --git a/config/server.ts b/config/server.ts deleted file mode 100644 index a54a241..0000000 --- a/config/server.ts +++ /dev/null @@ -1,10 +0,0 @@ -export default ({ env }) => ({ - host: env('HOST', '0.0.0.0'), - port: env.int('PORT', 1337), - app: { - keys: env.array('APP_KEYS'), - }, - webhooks: { - populateRelations: env.bool('WEBHOOKS_POPULATE_RELATIONS', false), - }, -}); diff --git a/server.js b/server.js new file mode 100644 index 0000000..23e797a --- /dev/null +++ b/server.js @@ -0,0 +1,3 @@ +const strapi = require("@strapi/strapi"); +const app = strapi({ distDir: "./dist" }); +app.start(); diff --git a/src/admin/app.example.tsx b/src/admin/app.example.tsx deleted file mode 100644 index 7316221..0000000 --- a/src/admin/app.example.tsx +++ /dev/null @@ -1,35 +0,0 @@ -export default { - config: { - locales: [ - // 'ar', - // 'fr', - // 'cs', - // 'de', - // 'dk', - // 'es', - // 'he', - // 'id', - // 'it', - // 'ja', - // 'ko', - // 'ms', - // 'nl', - // 'no', - // 'pl', - // 'pt-BR', - // 'pt', - // 'ru', - // 'sk', - // 'sv', - // 'th', - // 'tr', - // 'uk', - // 'vi', - // 'zh-Hans', - // 'zh', - ], - }, - bootstrap(app) { - console.log(app); - }, -}; diff --git a/src/admin/tsconfig.json b/src/admin/tsconfig.json deleted file mode 100644 index 9be5078..0000000 --- a/src/admin/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "@strapi/typescript-utils/tsconfigs/admin", - "include": [ - "../plugins/**/admin/src/**/*", - "./" - ], - "exclude": [ - "node_modules/", - "build/", - "dist/", - "**/*.test.ts" - ] -} diff --git a/src/admin/webpack.config.example.js b/src/admin/webpack.config.example.js deleted file mode 100644 index 1ca45c2..0000000 --- a/src/admin/webpack.config.example.js +++ /dev/null @@ -1,9 +0,0 @@ -'use strict'; - -/* eslint-disable no-unused-vars */ -module.exports = (config, webpack) => { - // Note: we provide webpack above so you should not `require` it - // Perform customizations to webpack config - // Important: return the modified config - return config; -}; diff --git a/src/api/.gitkeep b/src/api/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/extensions/.gitkeep b/src/extensions/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/src/index.ts b/src/index.ts deleted file mode 100644 index 9fca261..0000000 --- a/src/index.ts +++ /dev/null @@ -1,18 +0,0 @@ -export default { - /** - * An asynchronous register function that runs before - * your application is initialized. - * - * This gives you an opportunity to extend code. - */ - register(/*{ strapi }*/) {}, - - /** - * An asynchronous bootstrap function that runs before - * your application gets started. - * - * This gives you an opportunity to set up your data model, - * run jobs, or perform some special logic. - */ - bootstrap(/*{ strapi }*/) {}, -};