Docker

To get started

docker run -dp 80:80 docker/getting-started

Container

Common Features

chroot in Linux

A chroot command on Unix operating systems is an operation that changes the apparent root directory for the current running process and its children. When you change root to another directory you cannot access files and commands outside that directory. This directory is called a chroot jail.

pivot_root in Linux

Changes the root mount in the mount namespace of the calling process. More precisely, it moves the root mount to the directory put_old and makes new_root the new root mount.

Has the benefit of putting the old mounts into a separate directory. These old mounts could be unmounted afterwards to make the filesystem completely invisible to broken out processes.

Container Image

When running a container, it uses an isolated filesystem. This custom filesystem is provided by a container image. Since the image contains the container's filesystem, it must contain everything needed to run an application - all dependencies, configuration, scripts, binaries, etc. The image also contains other configuration for the container, such as environment variables, a default command to run, and other metadata.

Example: 1

Sharing the App

Testing your images

http://play-with-docker.com/

Create instance and test your app.

Persisting our DB

Containers Filesystem

When a container runs, it uses the various layers from an image for its filesystem. Each container also gets its own "scratch space" to create/update/remove files. Any changes won't be seen in another container, even if they are using the same image.

Container Volumes

Volumes provide the ability to connect specific filesystem paths of the container back to the host machine. If a directory in the container is mounted, changes in that directory are also seen on the host machine. If we mount that same directory across container restarts, we'd see the same files.

Persisting Data

By creating a volume and attaching (often called "mounting") it to the directory where the data is stored in , we can persist the data. If our container writes to the mounted directory, it will be persisted to the host in the volume.

Named Volume

Named Volume is simply a bucket of data. Docker maintains the physical location on the disk and we need to remember the name of the volume(Every time we use the volume)

 docker volume create todo-db
 docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started

Diving into our Volume

        $ docker volume inspect todo-db
        [
            {
                "CreatedAt": "2020-03-26T21:05:29+05:30",
                "Driver": "local",
                "Labels": {},
                "Mountpoint": "/var/lib/docker/volumes/todo-db/_data",
                "Name": "todo-db",
                "Options": {},
                "Scope": "local"
            }
        ]

Note: Generally We will need to have root access to access this directory from the host.

Bind Mounts

With bind mounts, we control the exact mountpoint on the host. We can use this to persist data, but is often used to provide additional data into containers. When working on an application, we can use a bind mount to mount our source code into the container to let it see code changes, respond, and let us see the changes right away.

Starting a Dev-Mode Container

* -w /app - sets the "working directory" or the current directory that the command will run from

Note: Bind mounts is very common for local development setups

Rule of Thumb

each container should do one thing and do it well

Some of the Reasons

Container Networking

If two containers are on the same network, they can talk to each other. If they aren't, they can't.

Enter the password and give show databases

    mysql> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | sys                |
    | todos              |
    +--------------------+
    5 rows in set (0.00 sec)

MYSQl Environmental Variables

Docker Compose

Note: By default, Docker Compose automatically creates a network specifically for the application stack (which is why we didn't define one in the compose file).

TO Check the logs

    docker-compose logs -f

The -f flag "follows" the log, so will give you live output as it's generated.

    docker-compose down
    docker-compose down --volumes # Remove volumes as well

Best Practices

$ docker image history getting-started

IMAGE               CREATED       CREATED BY                                      SIZE  
2fd3a9645cf6        5 hours ago   /bin/sh -c #(nop)  CMD ["node" "/app/src/ind…   0B                  
ffa2a47db0b7        5 hours ago   /bin/sh -c yarn install --production            83.2MB              
296afaf1a376        5 hours ago   /bin/sh -c #(nop) COPY dir:1bc092cfe17c580ca…   4.63MB              
9c5526543a3f        6 hours ago   /bin/sh -c #(nop) WORKDIR /app                  0B                  
f77abbe89ac1        2 days ago    /bin/sh -c #(nop)  CMD ["node"]                 0B                  
<missing>           2 days ago    /bin/sh -c #(nop)  ENTRYPOINT ["docker-entry…   0B                  
<missing>           2 days ago    /bin/sh -c #(nop) COPY file:238737301d473041…   116B                
<missing>           2 days ago    /bin/sh -c apk add --no-cache --virtual .bui…   7.62MB              
<missing>           2 days ago    /bin/sh -c #(nop)  ENV YARN_VERSION=1.22.0      0B                  
<missing>           2 days ago    /bin/sh -c addgroup -g 1000 node     && addu…   74.9MB              
<missing>           2 days ago    /bin/sh -c #(nop)  ENV NODE_VERSION=12.16.1     0B                  
<missing>           2 days ago    /bin/sh -c #(nop)  CMD ["/bin/sh"]              0B                  
<missing>           2 days ago    /bin/sh -c #(nop) ADD file:0c4555f363c2672e3…   5.6MB 

Once a layer changes, all downstream layers have to be recreated as well

Multi-Stage Builds

Multi-stage builds are an incredibly powerful tool to help use multiple stages to create an image. There are several advantages for them:

Maven/Tomcat Example

When building Java-based applications, a JDK is needed to compile the source code to Java bytecode. However, that JDK isn't needed in production. Also, you might be using tools like Maven or Gradle to help build the app. Those also aren't needed in our final image. Multi-stage builds help.

    FROM maven AS build
    WORKDIR /app
    COPY . .
    RUN mvn package

    FROM tomcat
    COPY --from=build /app/target/file.war /usr/local/tomcat/webapps 

In this example, we use one stage (called build) to perform the actual Java build using Maven. In the second stage (starting at FROM tomcat), we copy in files from the build stage. The final image is only the last stage being created (which can be overridden using the --target flag).

React Example

When building React applications, we need a Node environment to compile the JS code (typically JSX), SASS stylesheets, and more into static HTML, JS, and CSS. If we aren't doing server-side rendering, we don't even need a Node environment for our production build. Why not ship the static resources in a static nginx container?

    FROM node:12 AS build
    WORKDIR /app
    COPY package* yarn.lock ./
    RUN yarn install
    COPY public ./public
    COPY src ./src
    RUN yarn run build

    FROM nginx:alpine
    COPY --from=build /app/build /usr/share/nginx/html

Here, we are using a node:12 image to perform the build (maximizing layer caching) and then copying the output into an nginx container.