Reputation: 1025
A total Docker newbie here.
I have a web application that uses two repositories. One of the repositories is basically a 'client' app, while the second one is the server. The server serves the static files from the client app.
I would like to dockerize the whole thing. In order to do so, now I'm wondering what is the best practice for this:
Or
Or
The first approach is working actually, but it seems wasteful since the image is now very big and contains disposal files.
The second approach feels "better" but when I run docker-compose up
from the bash script I can't copy the files already, since the script is already running:
#!/bin/bash
git clone ... ~/tmp/client
(cd ~/tmp/client && yarn && yarn build && mv build ~/tmp/build)
docker-compose up
rm -rf ~/tmp/client
As for the third approach I don't even know how to do that.
Any suggestion or reference would be very helpful.
Upvotes: 4
Views: 2986
Reputation: 12260
Great question! Even though there are several ways to solve this, there are quite some differences and drawbacks with some of these approaches. Back in the days the pattern was basically to build stuff outside (on the host) and then copy the relevant things into the image if you wanted to avoid having all the SDKs and sources in your production image.
Luckily there are better ways to solve this today: multistage docker builds.
A multistage Dockerfile is like a regular Dockerfile but it contains several stages (aka more than one FROM
statement). Each stage is a fresh start of an image build. Not all images might end up in your container registry as some of them are just used to trigger intermediate build steps.
Pseudo code
FROM node:version AS frontend-build
WORKDIR /src
COPY src/frontend . # or better package.json/package-lock.json first, then install, then the rest
RUN npm ci # or yarn build
FROM jdk-plus-buildtool:version AS backend-build
WORKDIR /app
COPY src/backend .
RUN mvn package # or similar
FROM trimmed-down-runtime:version
WORKDIR /app
COPY --from=backend-build target/myapp/ .
COPY --from=frontend-build dist/ ./static-files-folder
CMD your-run-command # or entrypoint
Using this approach has several advantages:
If you are talking about a static javascript application and an HTTP API backend server, you could also use two separate images (frontend and backend) and then set up network and proxying accordingly so that you only expose the frontend container to the world and all requests are routed through the frontend to the backend application.
One more comment: You are talking about different repositories for client and server. Usually the CI environment cares about checking out the desired versions of your code before the real build starts. If this server is basically used from this one client only, I would use the bundled approach and also move the client sources into a subfolder of the main server repository. This makes it easier to do bugfixes for the whole system with a single bugfix branch. If you really cannot move source code between repositories, I would go with some git submodule/subtree approach to avoid dealing with commit references on my own during the build.
Upvotes: 3