feat: merge front and server dockerfiles and optimize build (#4589)

* feat: merge front and server dockerfiles and optimize build

* fix: update image label

* fix: bring back support for REACT_APP_SERVER_BASE_URL injection at runtime

* fix: remove old entries & add nx cache in dockerignore

* feat: generate frontend config at runtime using Nest

* fix: format and filename

* feat: use the EnvironmentService and leave default blank

* feat: add support for DB migrations
This commit is contained in:
Quentin G 2024-03-21 19:22:21 +01:00 committed by GitHub
parent 3fa8c4bace
commit 1aa48d3bf7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 146 additions and 3 deletions

View File

@ -1,2 +1,4 @@
server/node_modules/ .git
server/.env .env
node_modules
.nx/cache

View File

@ -29,6 +29,12 @@ prod-docs-build:
prod-docs-run: prod-docs-run:
@docker run -d -p 3000:3000 --name twenty-docs twenty-docs @docker run -d -p 3000:3000 --name twenty-docs twenty-docs
prod-build:
@cd ../.. && docker build -f ./packages/twenty-docker/prod/twenty/Dockerfile --tag twenty . && cd -
prod-run:
@docker run -d -p 3000:3000 --name twenty twenty
prod-front-build: prod-front-build:
@cd ../.. && docker build -f ./packages/twenty-docker/prod/twenty-front/Dockerfile --tag twenty-front . && cd - @cd ../.. && docker build -f ./packages/twenty-docker/prod/twenty-front/Dockerfile --tag twenty-front . && cd -

View File

@ -0,0 +1,77 @@
# Base image for common dependencies
FROM node:18.17.1-alpine as common-deps
WORKDIR /app
# Copy only the necessary files for dependency resolution
COPY ./package.json ./yarn.lock ./.yarnrc.yml ./tsconfig.base.json ./nx.json /app/
COPY ./.yarn/releases /app/.yarn/releases
COPY ./packages/twenty-emails/package.json /app/packages/twenty-emails/
COPY ./packages/twenty-server/package.json /app/packages/twenty-server/
COPY ./packages/twenty-server/patches /app/packages/twenty-server/patches
COPY ./packages/twenty-ui/package.json /app/packages/twenty-ui/
COPY ./packages/twenty-front/package.json /app/packages/twenty-front/
# Install all dependencies
RUN yarn && yarn cache clean && npx nx reset
# Build the back
FROM common-deps as twenty-server-build
# Copy sourcecode after installing dependences to accelerate subsequents builds
COPY ./packages/twenty-emails /app/packages/twenty-emails
COPY ./packages/twenty-server /app/packages/twenty-server
RUN npx nx run twenty-server:build && \
mv /app/packages/twenty-server/dist /app/packages/twenty-server/build && \
npx nx run twenty-server:build:packageJson && \
mv /app/packages/twenty-server/dist/package.json /app/packages/twenty-server/package.json && \
rm -rf /app/packages/twenty-server/dist && \
mv /app/packages/twenty-server/build /app/packages/twenty-server/dist
RUN yarn workspaces focus --production twenty-emails twenty-server
# Build the front
FROM common-deps as twenty-front-build
ARG REACT_APP_SERVER_BASE_URL
COPY ./packages/twenty-front /app/packages/twenty-front
COPY ./packages/twenty-ui /app/packages/twenty-ui
RUN yarn nx build twenty-front
# Final stage: Run the application
FROM node:18.17.1-alpine as twenty
# Used to run healthcheck in docker
RUN apk add --no-cache curl jq
COPY ./packages/twenty-docker/prod/twenty/entrypoint.sh /app/entrypoint.sh
RUN chmod +x /app/entrypoint.sh
WORKDIR /app/packages/twenty-server
ARG REACT_APP_SERVER_BASE_URL
ENV REACT_APP_SERVER_BASE_URL $REACT_APP_SERVER_BASE_URL
# Copy built applications from previous stages
COPY --chown=1000 --from=twenty-server-build /app /app
COPY --chown=1000 --from=twenty-server-build /app/packages/twenty-server /app/packages/twenty-server
COPY --chown=1000 --from=twenty-front-build /app/packages/twenty-front/build /app/packages/twenty-server/dist/front
# Set metadata and labels
LABEL org.opencontainers.image.source=https://github.com/twentyhq/twenty
LABEL org.opencontainers.image.description="This image provides a consistent and reproducible environment for the backend and frontend, ensuring it deploys faster and runs the same way regardless of the deployment environment."
RUN mkdir /app/.local-storage
RUN chown -R 1000 /app
# Use non root user with uid 1000
USER 1000
CMD ["node", "dist/src/main"]
ENTRYPOINT ["/app/entrypoint.sh"]

View File

@ -0,0 +1,17 @@
#!/bin/sh
# Check if the initialization has already been done and that we enabled automatic migration
if [ "${ENABLE_DB_MIGRATIONS}" = "true" ] && [ ! -f /app/${STORAGE_LOCAL_PATH}/db_initialized ]; then
echo "Running database setup and migrations..."
# Run setup and migration scripts
npx ts-node ./scripts/setup-db.ts
yarn database:migrate:prod
# Mark initialization as done
echo "Successfuly migrated DB!"
touch /app/${STORAGE_LOCAL_PATH}/db_initialized
fi
# Continue with the original Docker command
exec "$@"

View File

@ -41,3 +41,7 @@ This should work out of the box with the eslint extension installed. If this doe
"source.fixAll.eslint": "explicit" "source.fixAll.eslint": "explicit"
} }
``` ```
## Docker container build
To successfully build Docker images, ensure that your system has a minimum of 2GB of memory available. For users of Docker Desktop, please verify that you've allocated sufficient resources to Docker within the application's settings.

View File

@ -44,7 +44,8 @@
"graphql-middleware": "^6.1.35", "graphql-middleware": "^6.1.35",
"jwt-decode": "^4.0.0", "jwt-decode": "^4.0.0",
"passport": "^0.7.0", "passport": "^0.7.0",
"psl": "^1.9.0" "psl": "^1.9.0",
"tsconfig-paths": "^4.2.0"
}, },
"devDependencies": { "devDependencies": {
"@nestjs/cli": "10.3.0", "@nestjs/cli": "10.3.0",

View File

@ -11,6 +11,7 @@ import '@sentry/tracing';
import { AppModule } from './app.module'; import { AppModule } from './app.module';
import { generateFrontConfig } from './utils/generate-front-config';
import { settings } from './engine/constants/settings'; import { settings } from './engine/constants/settings';
import { LoggerService } from './engine/integrations/logger/logger.service'; import { LoggerService } from './engine/integrations/logger/logger.service';
import { EnvironmentService } from './engine/integrations/environment/environment.service'; import { EnvironmentService } from './engine/integrations/environment/environment.service';
@ -60,6 +61,9 @@ const bootstrap = async () => {
}), }),
); );
// Create the env-config.js of the front at runtime
generateFrontConfig();
await app.listen(app.get(EnvironmentService).get('PORT')); await app.listen(app.get(EnvironmentService).get('PORT'));
}; };

View File

@ -0,0 +1,31 @@
import * as fs from 'fs';
import * as path from 'path';
import { ConfigService } from '@nestjs/config';
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
const environmentService = new EnvironmentService(new ConfigService());
export function generateFrontConfig(): void {
const configObject = {
window: {
_env_: {
REACT_APP_SERVER_BASE_URL: environmentService.get('SERVER_URL'),
},
},
};
const configString = `window._env_ = ${JSON.stringify(
configObject.window._env_,
null,
2,
)};`;
const distPath = path.join(__dirname, '../..', 'front');
if (!fs.existsSync(distPath)) {
fs.mkdirSync(distPath, { recursive: true });
}
fs.writeFileSync(path.join(distPath, 'env-config.js'), configString, 'utf8');
}

View File

@ -45763,6 +45763,7 @@ __metadata:
passport: "npm:^0.7.0" passport: "npm:^0.7.0"
psl: "npm:^1.9.0" psl: "npm:^1.9.0"
rimraf: "npm:^5.0.5" rimraf: "npm:^5.0.5"
tsconfig-paths: "npm:^4.2.0"
typescript: "npm:^5.3.3" typescript: "npm:^5.3.3"
languageName: unknown languageName: unknown
linkType: soft linkType: soft