Dockerize your application
DockerFile example
Add a dockerfile in your project root.
Notice: the file name is
Dockerfile
with no extension, do not misspell.
For a simple vue project, we need a node image. Prefer alpine, a much smaller distribution.
FROM node:21-alpine3.17
Back to terminal, we build it. There we go.
docker build --tag vue-app .
The .
refers to which folder the dockerfile is placed.
Include files into image
All folders and files are file in linux.
COPY
and ADD
are two different keywords to do the same thing: Add files into a image
COPY
FROM node:21-alpine3.17
COPY <...source> <dest>
2
COPY
supports syntax just like linux, we can apply multiple files or pattern to represent the source. <dest>
supports both relative and absolute, it refers to the path in container. This approach doesn't allow files containing any space, so we use array to pass the args.
FROM node:21-alpine3.17
COPY ["package.json", "tsconfig.json"] <dest>
2
ADD
ADD
keyword has an additional feature, add from url. We can compose ADD
and COPY
together.
From Url
FROM node:21-alpine3.17
COPY ["package.json", "tsconfig.json"] <dest>
ADD http://.../route <dest>
2
3
If we pass a compressed file to ADD
, it will automatically decompress it.
Auto Decompression
FROM node:21-alpine3.17
COPY ["package.json", "tsconfig.json"] <dest>
ADD ./files.zip/ <dest>
2
3
Rebuild to see what happens
Now let's rebuild the image.
FROM node:alpine
WORKDIR /app
COPY . .
2
3
docker build --tag vue-app .
There are tons of files(184.22MB ) were transferred into image, mostly are native dependencies.
docker build --tag vue-app .
2023/11/09 20:54:31 http2: server: error reading preface from client //./pipe/docker_engine: file has already been closed
[+] Building 21.8s (9/9) FINISHED docker:default
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 77B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [internal] load metadata for docker.io/library/node:alpine 2.7s
=> [auth] library/node:pull token for registry-1.docker.io 0.0s
=> CACHED [1/3] FROM docker.io/library/node:alpine@sha256:df76a9449df49785f89d517764012e3396b063ba3e746e8d88f36e9f332b1864 0.0s
=> [internal] load build context 13.5s
=> => transferring context: 184.22MB 13.4s
=> [2/3] WORKDIR /app 0.1s
=> [3/3] COPY . . 2.5s
=> exporting to image 3.0s
=> => exporting layers 3.0s
=> => writing image sha256:5c81ba5b990c7eb84aec2fb2bb34c64bc7201ff753ebf7f5b59fbedc1e87d484 0.0s
=> => naming to docker.io/library/vue-app 0.0s
What's Next?
View a summary of image vulnerabilities and recommendations → docker scout quickview
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
And check the file system using shell. We are right in the default directory /app
as WORKDIR
specified.
docker run -it vue-app sh
/app #
/app # ls
Dockerfile babel.config.js package-lock.json public tsconfig.json
README.md node_modules package.json src vue.config.js
/app #
2
3
4
5
6
7
Exclude files
For native dependencies, they are unnecessarily copied into image.
.dockerignore
.dockerignore
(all lower case) is the file to specify those you want to exclude from being copied.
Now, ignore node_modules/
where those packages are stored!
node_modules/
And rebuild the image, transferred files reduced to 755B.
docker build --tag vue-app .
[+] Building 4.5s (9/9) FINISHED docker:default
=> [internal] load .dockerignore 0.0s
=> => transferring context: 53B 0.0s
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 77B 0.0s
=> [internal] load metadata for docker.io/library/node:alpine 3.8s
=> [auth] library/node:pull token for registry-1.docker.io 0.0s
=> [1/3] FROM docker.io/library/node:alpine@sha256:df76a9449df49785f89d517764012e3396b063ba3e746e8d88f36e9f332b1864 0.0s
=> [internal] load build context 0.6s
=> => transferring context: 755B 0.6s
=> CACHED [2/3] WORKDIR /app 0.0s
=> [3/3] COPY . . 0.0s
=> exporting to image 0.0s
=> => exporting layers 0.0s
=> => writing image sha256:3cc74d8ddc32ee4affcd880ce341f2e108b45db68c4208eccfdc7aca217a8a3f 0.0s
=> => naming to docker.io/library/vue-app 0.0s
What's Next?
View a summary of image vulnerabilities and recommendations → docker scout quickview
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
But without these dependencies, how do we run the application in container? That's why RUN
exists for automating executions.
Automate with RUN
All commands for
RUN
must be executable for corresponding linux/container. For multiple command, should use string array or repeatRUN
after previousRUN
.
FROM node:alpine
WORKDIR /app
COPY . .
RUN npm install
RUN apt update && touch ./hello.txt
2
3
4
5
Set Environment Variables
FROM node:alpine
WORKDIR /app
COPY . .
RUN npm install
ENV API_URL=http://api.myapp.com
2
3
4
5
Check variables after rebuilding. There it is.
/app # echo $API_URL
http://api.myapp.com
/app #
2
3
EXPOSE
As we launch the server in container, we cannot access it with port specified by node since it's inside the container, so we need EXPOSE
the map the port for external connection.
FROM node:alpine
WORKDIR /app
COPY . .
RUN npm install
ENV API_URL=http://api.myapp.com
EXPOSE 8080
2
3
4
5
6