Docker build!
Sample Application
Let’s starts with a simple Node.js application
Dockerfile
FROM node:14-alpine
WORKDIR /code
COPY package.json /code/package.json (1)
RUN npm install \ (2)
&& npm install -g nodemon@1.11.0 \ (3)
&& npm cache clean --force; (4)
COPY app.js /code (5)
COPY index.html /code (5)
CMD ["npm", "start"] (6)
1 | Copy package.json file |
2 | Install the dependencies in the local node_modules folder. |
3 | Install global |
4 | Clean cache |
5 | Copy NodeJS application |
6 | Run application |
Dockerfile instructions
FROM
The FROM instruction initializes a new build stage and sets the Base Image for subsequent instructions.
As such, a valid Dockerfile must start with a FROM instruction. The image can be any valid image
We recommend the Alpine image as it is tightly controlled and small in size (currently under 5 MB), while still being a full Linux distribution. |
LABEL
The LABEL instruction adds metadata to an image. A LABEL is a key-value pair. To include spaces within a LABEL value, use quotes and backslashes as you would in command-line parsing.
A example:
LABEL "com.example.vendor"="ACME Incorporated"
LABEL com.example.label-with-value="foo"
LABEL version="1.0"
LABEL description="This text illustrates \
that label-values can span multiple lines."
RUN
RUN has 2 forms:
-
RUN <command> (shell form, the command is run in a shell, which by default is /bin/sh -c on Linux or cmd /S /C on Windows)
-
RUN ["executable", "param1", "param2"] (exec form)
The RUN instruction will execute any commands in a new layer on top of the current image and commit the results. The resulting committed image will be used for the next step in the Dockerfile.
Split long or complex RUN statements on multiple lines separated with backslashes to make your Dockerfile more readable, understandable, and maintainable. For example:
|
CMD
The main purpose of a CMD is to provide defaults for an executing container.
The CMD instruction has three forms:
-
CMD ["executable","param1","param2"] (exec form, this is the preferred form)
-
CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
-
CMD command param1 param2 (shell form)
There can only be one CMD instruction in a Dockerfile. If you list more than one CMD then only the last CMD will take effect. |
EXPOSE
The EXPOSE instruction indicates the ports on which a container listens for connections.
EXPOSE 8000
The EXPOSE instruction informs Docker that the container listens on the specified network ports at runtime. You can specify whether the port listens on TCP or UDP, and the default is TCP if the protocol is not specified. |
ENV
To make new software easier to run, you can use ENV
For example
ENV PATH=/usr/local/nginx/bin:$PATH
ensures that CMD ["nginx"] just works.
ENV PG_MAJOR=9.3
ENV PG_VERSION=9.3.4
RUN curl -SL https://example.com/postgres-$PG_VERSION.tar.xz | tar -xJC /usr/src/postgress && …
ENV PATH=/usr/local/postgres-$PG_MAJOR/bin:$PATH
ADD or COPY
Although ADD and COPY are functionally similar.
|
COPY
COPY has two forms:
COPY [--chown=<user>:<group>] <src>... <dest>
COPY [--chown=<user>:<group>] ["<src>",... "<dest>"]
e.g.
COPY home /mydir/
COPY --chown=55:mygroup files* /somedir/
COPY --chown=bin files* /somedir/
COPY --chown=1 files* /somedir/
COPY --chown=10:11 files* /somedir/
The COPY instruction copies new files or directories from <src> and adds them to the filesystem of the container at the path <dest>.
ADD
ADD has two forms:
ADD [--chown=<user>:<group>] <src>... <dest>
ADD [--chown=<user>:<group>] ["<src>",... "<dest>"]
e.g.
ADD home /mydir/
ADD --chown=55:mygroup files* /somedir/
ADD --chown=bin files* /somedir/
ADD --chown=1 files* /somedir/
ADD --chown=10:11 files* /somedir/
The ADD instruction copies new files, directories or remote file URLs from <src> and adds them to the filesystem of the image at the path <dest>
ENTRYPOINT
ENTRYPOINT has two forms:
The exec form, which is the preferred form:
ENTRYPOINT ["executable", "param1", "param2"]
The shell form:
ENTRYPOINT command param1 param2
An ENTRYPOINT allows you to configure a container that will run as an executable.
docker run -i -t --rm -p 80:80 nginx
Let’s see with an example of an image for the command line tool s3cmd:
ENTRYPOINT ["s3cmd"]
CMD ["--help"]
Now the image can be run like this to show the command’s help:
docker run s3cmd
USER
The USER instruction sets the user name (or UID) and optionally the user group (or GID) to use when running the image and for any RUN, CMD and ENTRYPOINT instructions that follow it in the Dockerfile.
If a service can run without privileges, use USER to change to a non-root user.
FROM alpine
USER swarmlab
WORKDIR
The WORKDIR instruction sets the working directory for any RUN, CMD, ENTRYPOINT, COPY and ADD instructions that follow it in the Dockerfile.
If the WORKDIR doesn’t exist, it will be created even if it’s not used in any subsequent Dockerfile instruction.
For clarity and reliability, you should always use absolute paths for your WORKDIR |
package.json
{
"main": "app.js",
"dependencies": {
"express": "~4.14.0",
"express-handlebars": "~3.0.0"
}
}
A package.json file:
|
app.js
var express = require('express');
var expressHandlebars = require('express-handlebars');
var http = require('http');
var PORT = 8000;
var LINES = [
"Ποιος μας γηροκομεί τη σήμερον ημέρα, ψηστιέρα, καρβουνιέρα μούσα δεκεμβριανή.",
"Πολέμησα καιρό σε όλα τα πεδία και με τυφλή μανία ξέσκιζα τον εχθρό.",
"Τώρα με χειρουργεί η αλλήθωρη νεολαία, μια τσογλανοπαρέα, που κάνει κριτική.",
];
var lineIndex = 0;
var app = express();
app.engine('html', expressHandlebars());
app.set('view engine', 'html');
app.set('views', __dirname);
app.get('/', function(req, res) {
var message = LINES[lineIndex];
lineIndex += 1;
if (lineIndex >= LINES.length) {
lineIndex = 0;
}
res.render('index', {message: message});
});
http.Server(app).listen(PORT, function() {
console.log("HTTP server listening on port %s", PORT);
});
index.html
<html>
<head>
<meta http-equiv="refresh" content="2">
<style type="text/css">
body {
font-family: Helvetica, Arial, sans-serif;
font-weight: 600;
font-size: 56pt;
text-transform: uppercase;
text-align: center;
background: #3c3;
color: white;
}
</style>
</head>
<body>“{{message}}”</body>
</html>