-
we start with a small node app
-
we add a Dockerfile containing instructions for building an image for our container.
Commands are run sequentially, and each command is run in an intermediate container. This is logged when building the image.
Commands are case-insensitive, but convention is to UPPERCASE them.
# FROM must be the first instruction in a Dockerfile # FROM specifies the base image from which an image will be built FROM mhart/alpine-node # COPY has the format: # COPY <src> <dest> # Files are copied from the host src to the provided destination inside the # container # The path of the source files is relative to the context of the build # (defined when running the build command that will create the image). COPY index.js . # EXPOSE informs Docker that the container listens on the specified ports at # runtime # THis does not publish the port - it is a type of documentation for the # person who will be running the container - "This container exposes port 3000" # -p is still responsible for publishing the port when using `docker run` EXPOSE 3000 # There can only be one CMD instruction in a Dockerfile # CMD provides defaults for an executing container # Only the last CMD will take effect CMD node index.js
-
Dockerfiles are used to build images along with a context. A build's files are located by a specified context, that being
PATH
,URL
, or-
. A build can then reference files in the context, such as withCOPY
. All files at the provided context get sent to the Docker deamon in order for an image to be built - not only the files used in theCOPY
command inside the Dockerfile..dockerignore
can be used to ignore files from the context and thus reduce the size of the uploaded context.The
build
command has the following syntax:$ docker build [OPTIONS] PATH | URL | -
We can build an image, using a tag to make it easier to reference, using the current directory as the context for the image:
$ docker build -t foo/node . # [1] [ 2 ] [3] # 1 - use docker's 'build' command to build an image from a Dockerfile. # Because we're not specifying a Dockerfile, it looks for one in the # current directory # 2 - build the image with the provided tag. We can reference docker to run # this image using foo/node once it's built # 3 - the context for the image will be the current folder
Once built, we can run a container using that image:
$ docker run -d -p 3000:3000 --name node-app foo/node # [1] [ 2 ] [ 3 ] [ 4 ] # 1 - run as a background daemon # 2 - publish 3000 from the container (2nd value) to be accessible via 3000 # on the host machine (first number) # 3 - name this container so it can be referenced later. After stopping this # container we can start it with: # docker run node-app # 4 - run this container using the image foo/node that we built
We can see which images are on the system using:
$ docker images
and remove an images using:
$ docker rmi [image-name]
-
Before creating the proxy, let's test that we can get nginx running:
$ docker run --rm -p 8000:80 nginx # [ 1 ] [ 2 ] [3] # 1 - remove this container when it's stopped # 2 - map 8000 on the host to 80 in the container - nginx's default port # 3 - run this container using the latest nginx image
Because we're using this container as a proxy, we won't be copying files into it.
-
A proxy has been created in
./05-app/nginx
. We create a default config for nginx with aproxy_pass
to proxy all requests, and we create a Dockerfile which, using the default nginx image, copies that config into a specified location inside the image so that the container will run with our nginx config instead of the default.We then build an image with the tag
foo/nginx
from that Dockerfile:$ cd 05-app/nginx $ docker build -t foo/nginx .
-
Now that we have an image for the proxy (tagged
foo/nginx
) we run a container using it as the base image.$ docker run -p 8000:80 --link node-app:app --name nginx-proxy foo/nginx # [ 1 ] [ 2 ] [ 3 ] [ 4 ] # 1 - create a container binding 8000 on the host to 80 in the container # (nginx's default) # 2 - link the currently running 'node-app' to this container, giving it # an alias of 'app'. The alias is the same as the # 3 - give the container a name so we can use `docker start nginx-proxy` # later, or reference the container elsewhere # 4 - run this container using the foo/nginx image
With the
node-app
container running, and thenginx-proxy
container running, we can access the app vialocalhost:3000
directly, or via the proxy atlocalhost:8000
-
Docker's
--link
flag is deprecated. Instead, it's recommended to use a user-defined bridge.First, create a network:
$ docker network create my-net
When creating a container, the network can be specified there:
$ docker run -d -p 8000:80 --network my-net --name nginx-proxy foo/nginx
Existing containers can be connected to the network:
$ docker network connect my-net node-app --alias app # [1] [ 2 ] [ 3 ] [ 4 ] # 1 - use the network comman # 2 - to connect something to the existing my-net network # 3 - and that something we connect is the running container with the name of # 'node-app' # 4 - and we alias node-app with 'app' for our upstream in the nginx config
We now have 2 containers running, and both are connected to our user-defined network
my-net
:$ docker network inspect my-net # ... "Containers": { "94b017d18b8efda784fc6095c0ea8d9e57aebbf61c5460184417ab02ca2234fc": { "Name": "node-app", # ... }, "c50afd0d5ac18c2498bddf376a3220332c18107ba887b1f5155d624f144dd00c": { "Name": "nginx-proxy", # ... } }, # ...
We can access both our original app at
localhost:3000
, and at the proxy atlocalhost:8000
. -
to remove a network we need to first disconnect connected containers:
$ docker network disconnect my-net nginx-proxy
At this point we can no longer access our app via
localhost:8000
, but we can continue to do so via the app's original url atlocalhost:3000
.We can now disconnect our app from the network:
$ docker network disconnect my-net node-app
Inspecting
my-net
now shows no connected containers. It can now be removed:$ docker network remove my-net
And we can verify that:
$ docker network ls