Skip to content

Commit 1aa48d3

Browse files
authored
feat: merge front and server dockerfiles and optimize build (twentyhq#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
1 parent 3fa8c4b commit 1aa48d3

File tree

9 files changed

+146
-3
lines changed

9 files changed

+146
-3
lines changed

.dockerignore

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,4 @@
1-
server/node_modules/
2-
server/.env
1+
.git
2+
.env
3+
node_modules
4+
.nx/cache

packages/twenty-docker/Makefile

+6
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ prod-docs-build:
2929
prod-docs-run:
3030
@docker run -d -p 3000:3000 --name twenty-docs twenty-docs
3131

32+
prod-build:
33+
@cd ../.. && docker build -f ./packages/twenty-docker/prod/twenty/Dockerfile --tag twenty . && cd -
34+
35+
prod-run:
36+
@docker run -d -p 3000:3000 --name twenty twenty
37+
3238
prod-front-build:
3339
@cd ../.. && docker build -f ./packages/twenty-docker/prod/twenty-front/Dockerfile --tag twenty-front . && cd -
3440

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Base image for common dependencies
2+
FROM node:18.17.1-alpine as common-deps
3+
4+
WORKDIR /app
5+
6+
# Copy only the necessary files for dependency resolution
7+
COPY ./package.json ./yarn.lock ./.yarnrc.yml ./tsconfig.base.json ./nx.json /app/
8+
COPY ./.yarn/releases /app/.yarn/releases
9+
10+
COPY ./packages/twenty-emails/package.json /app/packages/twenty-emails/
11+
COPY ./packages/twenty-server/package.json /app/packages/twenty-server/
12+
COPY ./packages/twenty-server/patches /app/packages/twenty-server/patches
13+
COPY ./packages/twenty-ui/package.json /app/packages/twenty-ui/
14+
COPY ./packages/twenty-front/package.json /app/packages/twenty-front/
15+
16+
# Install all dependencies
17+
RUN yarn && yarn cache clean && npx nx reset
18+
19+
20+
# Build the back
21+
FROM common-deps as twenty-server-build
22+
23+
# Copy sourcecode after installing dependences to accelerate subsequents builds
24+
COPY ./packages/twenty-emails /app/packages/twenty-emails
25+
COPY ./packages/twenty-server /app/packages/twenty-server
26+
27+
RUN npx nx run twenty-server:build && \
28+
mv /app/packages/twenty-server/dist /app/packages/twenty-server/build && \
29+
npx nx run twenty-server:build:packageJson && \
30+
mv /app/packages/twenty-server/dist/package.json /app/packages/twenty-server/package.json && \
31+
rm -rf /app/packages/twenty-server/dist && \
32+
mv /app/packages/twenty-server/build /app/packages/twenty-server/dist
33+
34+
RUN yarn workspaces focus --production twenty-emails twenty-server
35+
36+
37+
# Build the front
38+
FROM common-deps as twenty-front-build
39+
40+
ARG REACT_APP_SERVER_BASE_URL
41+
42+
COPY ./packages/twenty-front /app/packages/twenty-front
43+
COPY ./packages/twenty-ui /app/packages/twenty-ui
44+
RUN yarn nx build twenty-front
45+
46+
47+
# Final stage: Run the application
48+
FROM node:18.17.1-alpine as twenty
49+
50+
# Used to run healthcheck in docker
51+
RUN apk add --no-cache curl jq
52+
53+
COPY ./packages/twenty-docker/prod/twenty/entrypoint.sh /app/entrypoint.sh
54+
RUN chmod +x /app/entrypoint.sh
55+
56+
WORKDIR /app/packages/twenty-server
57+
58+
ARG REACT_APP_SERVER_BASE_URL
59+
ENV REACT_APP_SERVER_BASE_URL $REACT_APP_SERVER_BASE_URL
60+
61+
# Copy built applications from previous stages
62+
COPY --chown=1000 --from=twenty-server-build /app /app
63+
COPY --chown=1000 --from=twenty-server-build /app/packages/twenty-server /app/packages/twenty-server
64+
COPY --chown=1000 --from=twenty-front-build /app/packages/twenty-front/build /app/packages/twenty-server/dist/front
65+
66+
# Set metadata and labels
67+
LABEL org.opencontainers.image.source=https://github.com/twentyhq/twenty
68+
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."
69+
70+
RUN mkdir /app/.local-storage
71+
RUN chown -R 1000 /app
72+
73+
# Use non root user with uid 1000
74+
USER 1000
75+
76+
CMD ["node", "dist/src/main"]
77+
ENTRYPOINT ["/app/entrypoint.sh"]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#!/bin/sh
2+
3+
# Check if the initialization has already been done and that we enabled automatic migration
4+
if [ "${ENABLE_DB_MIGRATIONS}" = "true" ] && [ ! -f /app/${STORAGE_LOCAL_PATH}/db_initialized ]; then
5+
echo "Running database setup and migrations..."
6+
7+
# Run setup and migration scripts
8+
npx ts-node ./scripts/setup-db.ts
9+
yarn database:migrate:prod
10+
11+
# Mark initialization as done
12+
echo "Successfuly migrated DB!"
13+
touch /app/${STORAGE_LOCAL_PATH}/db_initialized
14+
fi
15+
16+
# Continue with the original Docker command
17+
exec "$@"

packages/twenty-docs/docs/start/local-setup/troubleshooting.mdx

+4
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,7 @@ This should work out of the box with the eslint extension installed. If this doe
4141
"source.fixAll.eslint": "explicit"
4242
}
4343
```
44+
45+
## Docker container build
46+
47+
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.

packages/twenty-server/package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,8 @@
4444
"graphql-middleware": "^6.1.35",
4545
"jwt-decode": "^4.0.0",
4646
"passport": "^0.7.0",
47-
"psl": "^1.9.0"
47+
"psl": "^1.9.0",
48+
"tsconfig-paths": "^4.2.0"
4849
},
4950
"devDependencies": {
5051
"@nestjs/cli": "10.3.0",

packages/twenty-server/src/main.ts

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import '@sentry/tracing';
1111

1212
import { AppModule } from './app.module';
1313

14+
import { generateFrontConfig } from './utils/generate-front-config';
1415
import { settings } from './engine/constants/settings';
1516
import { LoggerService } from './engine/integrations/logger/logger.service';
1617
import { EnvironmentService } from './engine/integrations/environment/environment.service';
@@ -60,6 +61,9 @@ const bootstrap = async () => {
6061
}),
6162
);
6263

64+
// Create the env-config.js of the front at runtime
65+
generateFrontConfig();
66+
6367
await app.listen(app.get(EnvironmentService).get('PORT'));
6468
};
6569

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import * as fs from 'fs';
2+
import * as path from 'path';
3+
4+
import { ConfigService } from '@nestjs/config';
5+
import { EnvironmentService } from 'src/engine/integrations/environment/environment.service';
6+
7+
const environmentService = new EnvironmentService(new ConfigService());
8+
9+
export function generateFrontConfig(): void {
10+
const configObject = {
11+
window: {
12+
_env_: {
13+
REACT_APP_SERVER_BASE_URL: environmentService.get('SERVER_URL'),
14+
},
15+
},
16+
};
17+
18+
const configString = `window._env_ = ${JSON.stringify(
19+
configObject.window._env_,
20+
null,
21+
2,
22+
)};`;
23+
24+
const distPath = path.join(__dirname, '../..', 'front');
25+
26+
if (!fs.existsSync(distPath)) {
27+
fs.mkdirSync(distPath, { recursive: true });
28+
}
29+
30+
fs.writeFileSync(path.join(distPath, 'env-config.js'), configString, 'utf8');
31+
}

yarn.lock

+1
Original file line numberDiff line numberDiff line change
@@ -45763,6 +45763,7 @@ __metadata:
4576345763
passport: "npm:^0.7.0"
4576445764
psl: "npm:^1.9.0"
4576545765
rimraf: "npm:^5.0.5"
45766+
tsconfig-paths: "npm:^4.2.0"
4576645767
typescript: "npm:^5.3.3"
4576745768
languageName: unknown
4576845769
linkType: soft

0 commit comments

Comments
 (0)