redhat logo

Intro: Docker and Kubernetes training - Day 1

Christian Posta
10/19/2015

Who

ceposta

Principal Middleware Architect

Blog: http://blog.christianposta.com

Twitter: @christianposta

Email: christian@redhat.com

  • Committer on Apache ActiveMQ, Apache Camel, Fabric8

  • Technology evangelist, recovering consultant

  • Spent a lot of time working with one of the largest Microservices, web-scale, unicorn companies

  • Frequent blogger and speaker about open-source, cloud, microservices

Agenda

  • Intro / Prep Environments

  • Day 1: Docker Deep Dive

  • Day 2: Kubernetes Deep Dive

  • Day 3: Advanced Kubernetes: Concepts, Management, Middleware

  • Day 4: Advanced Kubernetes: CI/CD, open discussions

 

redhat logo

Docker Deep Dive

What is this Docker thing?

  • A company?

  • A format?

  • An API?

docker-logo

Linux containers? That’s not new…

  • Linux-native functionality

  • Has been around ~ 10 years?

  • cgroups

  • kernel namespaces

  • chroot

  • Linux capabilities

  • Security (SELinux)

linux

cgroups

  • Built into Kernel (RHEL7/Debian/etc)

  • Generically isolates resource usage (CPU, memory, disk, network)

  • Guarantee resources to app/set of apps

  • Can be adjusted on the fly

  • Can monitor the cgroup itself to see utilization

intro-cgroups

Kernel namespaces

  • Isolating views of the system

  • Can make a process think it’s the only process

  • Built-in way to "virtualize" a process

scope

Kernel namespaces

  • mnt (mount points, filesystem)

  • pid (processes)

  • net (network stack)

  • ipc (inter-process comms)

  • uts (hostname)

  • user (UIDs)

Linux capabilities

  • "root" has all capabilities

  • a fine-grained division of "root"'s permissions for a process

  • CAP_NET_ADMIN - modify routing tables, firewalling, NAT, etc

  • CAP_KILL - bypass any checks for sending the kill signals

  • CAP_SYS_ADMIN - mount, set hostname, etc

Docker brings together

docker

Why is this important?

  • Image format vs golden image

  • API

  • Packaging

  • Separation of concerns (Devs/Ops)

  • Density, infrastructure utilization

Docker format

docker-layers

Process virtualization

docker-animated-1

Immutable infrastructure

  • "We’ll put it back in Ansible"

  • Cattle vs Pets

  • Don’t change it; replace it

  • System created fully from automation; avoid drift

  • Manual intervention is error prone

  • How does Docker help?

cattle

Basic Docker components

  • Docker client

  • Docker daemon

  • Images

  • Registry

  • Containers

Basic Docker components

docker-components

Docker images

  • Templates from which containers are created

  • Layered using union filesystems

  • Each change to the system is a layer

  • Typically created with Dockerfiles/instructions

  • Stored in a docker registry (public/private)

Docker containers

  • Runtime instances of a Docker Image

  • Copy on write file system; changes localized

  • "virtualized" with namespaces, cgroups, selinux, etc

  • Has own IP address/networking/volumes

  • Intended to run single process (process virtualization)

Developer workflow

  • work from vagrant image

  • can trash and reboot it any time

  • locally running docker client

  • Source code in developer IDE

  • When ready, use tooling to generate docker image (or hand craft)

  • Run image locally (possibly with others)

  • Push code (or image?)

  • CI process kicks in

Developer works locally

workflow1

Developer pushes code

workflow2

 

redhat logo

Your First Docker!

Pull a docker image

Pull Centos7 from DockerHub (http://docker.io)

docker pull centos:7

output:

ceposta@postamac(~) $ docker pull centos:7
7: Pulling from library/centos
fa5be2806d4c: Pull complete
0cd86ce0a197: Pull complete
e9407f1d4b65: Pull complete
c9853740aa05: Pull complete
e9fa5d3a0d0e: Pull complete
Digest: sha256:def5c79bc29849815dec7dddc8f75530a9115c94d5b17e0e6807f929902fab62
Status: Downloaded newer image for centos:7

List docker images

List locally, installed images

docker images

output:

ceposta@postamac(~) $ docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
centos              7                   e9fa5d3a0d0e        2 days ago          172.3 MB

Show all images, including itermmediate

docker images -a

output:

ceposta@postamac(~) $ docker images -a
REPOSITORY          TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
centos              7                   e9fa5d3a0d0e        2 days ago          172.3 MB
<none>              <none>              c9853740aa05        2 days ago          172.3 MB
<none>              <none>              e9407f1d4b65        2 days ago          172.3 MB
<none>              <none>              0cd86ce0a197        2 days ago          172.3 MB
<none>              <none>              fa5be2806d4c        5 weeks ago         0 B

Let’s run a Docker container!

Let’s run a linux command inside a docker container:

docker run --rm centos:7 echo "hello world"

output:

ceposta@postamac(~) $ docker run --rm centos:7 echo "hello world"
hello world

Woah, what happened? It just printed out "hello, world"? So what?

Let’s run a Docker container!

Let’s run a shell inside a docker container:

docker run -it --rm centos:7 bash

output:

[root@d7dfcc490cbe /]# _

Cool! We have a bash shell, and a minimal distro of Centos 7! Did you see how fast that booted up? Typing ls -l /etc/*-release from the new bash prompt shows us we indeed have a Centos 7 distro:

[root@c2c2b8a65afe /]# ll /etc/*-release
-rw-r--r-- 1 root root  38 Mar 31  2015 /etc/centos-release
-rw-r--r-- 1 root root 393 Mar 31  2015 /etc/os-release
lrwxrwxrwx 1 root root  14 Aug 14 21:00 /etc/redhat-release -> centos-release
lrwxrwxrwx 1 root root  14 Aug 14 21:00 /etc/system-release -> centos-release

Let’s run a Docker container!

Run some other commands from within the container:

  hostname -f
  cat /etc/hosts
  ps aux
  yum -y install vim
  ip a

A real linux distro right? Did you notice that ps aux didn’t show too many processes?

Let’s run a Docker container!

Let’s do some destructive stuff:

rm -fr /usr/sbin

Wuh? you deleted all of the sacred system tools!?

Let’s delete some user tools too

rm -fr /usr/bin

output:

[root@c2c2b8a65afe /]# ls
bash: /usr/bin/ls: No such file or directory

Whoops… cannot ls or do anything useful anymore. What have we done!?

Let’s run a Docker container!

No worries! Just exit the container and fire up a new one:

docker run -it --rm centos:7 bash

Everything is back! Phew….

Deploy Apache Tomcat

Now let’s run a JVM based application like Apache Tomcat:

docker run --rm -p 8888:8080 tomcat:8.0

Since the Tomcat 8.0 docker image doesn’t exist, Docker will try to automatically pull it from the registry. Give it a moment, and you should see tomcat start successfully:

16-Oct-2015 18:30:51.541 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /usr/local/tomcat/webapps/manager has finished in 28 ms
16-Oct-2015 18:30:51.542 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /usr/local/tomcat/webapps/examples
16-Oct-2015 18:30:52.108 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /usr/local/tomcat/webapps/examples has finished in 566 ms
16-Oct-2015 18:30:52.117 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /usr/local/tomcat/webapps/ROOT
16-Oct-2015 18:30:52.161 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /usr/local/tomcat/webapps/ROOT has finished in 45 ms
16-Oct-2015 18:30:52.176 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
16-Oct-2015 18:30:52.206 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"]
16-Oct-2015 18:30:52.208 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 1589 ms

Deploy Apache Tomcat

Let’s explore that command for a quick sec:

docker run --rm -p 8888:8080 tomcat:8.0
  • --rm tells us that we want to remove the container (delete) when it’s done running

  • -p 8888:8080 tells us we want to map the container’s port 8080 to the host port of 8888

So if we try to connect to http://localhost:8888 we should be able to reach our tomcat server!

Deploy Apache Tomcat

Well, not quite. Why not?

docker-ports

Our Docker Host has been mapped properly, but we cannot reach it from our host (Windows/MacOSX) because the VM does not expose those ports.

Map ports for tomcat

Enable port forwarding between the VM Host (windows/Mac) and the VM Guest (Docker host):

port-forward

Map ports for tomcat

docker-host-ports

Deploy Apache Tomcat

Now navigate in a browser to http://localhost:8888

tomcat

Deploy Apache Tomcat

We have a running container that has tomcat in it! WooHoo! Let’s explore the tomcat container really quick. Fire up a new shell window (separate than the running tomcat docker container from previous)

docker ps

output:

ceposta@postamac(~) $ docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS                    NAMES
c2c059a3baab        tomcat:8.0          "catalina.sh run"   36 minutes ago      Up 36 minutes       0.0.0.0:8888->8080/tcp   dreamy_kowalevski

Let’s log into the container to explore:

docker exec -it <container_id> bash

We should now be at the bash prompt for the tomcat container. Feel free to explore around a bit.

Deploy Apache Tomcat

Now exit out of the tomcat container

exit

And switch back to the other window where we ran tomcat. Let’s CTR+C that window and exit the docker container.

We should have no containers running:

docker ps

Nor should we have any stopped containers:

docker ps -a

This is because we used the --rm command when we started the tomcat container, so it will automatically remove the container.

Deploy Apache Tomcat

Here are some other useful docker run flags:

  • --name give your container a unique name

  • -d run your container in daemon mode (in the background)

  • --dns give your container a different nameserver from the host

  • -it interactive with tty (wouldn’t use this with -d)

  • -e pass in environment variables to the container

  • --expose expose ports from the docker container

  • -P expose all published ports on the container

  • -p map a specific port from the container to the host host:container

We will look at --link and --volume later today.

Deploy Apache Tomcat as a Daemon

Let’s use some of those previous run command-line flags and start tomcat in the background:

docker run -d --name="tomcat8" -p 8888:8080 tomcat:8.0

Note, we also gave this container a name, so we can refer to it by name instead of container id:

docker logs tomcat8

output:

examples
16-Oct-2015 19:19:20.441 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /usr/local/tomcat/webapps/examples has finished in 526 ms
16-Oct-2015 19:19:20.447 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deploying web application directory /usr/local/tomcat/webapps/ROOT
16-Oct-2015 19:19:20.507 INFO [localhost-startStop-1] org.apache.catalina.startup.HostConfig.deployDirectory Deployment of web application directory /usr/local/tomcat/webapps/ROOT has finished in 60 ms
16-Oct-2015 19:19:20.515 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
16-Oct-2015 19:19:20.527 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["ajp-nio-8009"]
16-Oct-2015 19:19:20.547 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 1497 ms

Deploy Apache Tomcat as a Daemon

Let’s use a couple of interesting docker commands with our tomcat8 container:

docker top tomcat8

I know, a little misnamed — instead of the normal linux top container, it just displays the processes running in the container:

PID                 USER                COMMAND
5301                root                /usr/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.endorsed.dirs=/usr/local/tomcat/endorsed -classpath /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp org.apache.catalina.startup.Bootstrap start

Deploy Apache Tomcat as a Daemon

What about this one:

docker inspect tomcat8

Wow… that’s a lot of information about the container! We can also use a --format template to pick out specific info from that output (see https://docs.docker.com/reference/commandline/inspect/)

docker inspect --format='{{.NetworkSettings.IPAddress}}' tomcat8

or

docker inspect --format='{{.Config.Env}}' tomcat8

output:

ceposta@postamac(~) $   docker inspect --format='{{.Config.Env}}' tomcat8
[PATH=/usr/local/tomcat/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin LANG=C.UTF-8 JAVA_VERSION=7u79 JAVA_DEBIAN_VERSION=7u79-2.5.6-1~deb8u1 CATALINA_HOME=/usr/local/tomcat TOMCAT_MAJOR=8 TOMCAT_VERSION=8.0.28 TOMCAT_TGZ_URL=https://www.apache.org/dist/tomcat/tomcat-8/v8.0.28/bin/apache-tomcat-8.0.28.tar.gz]

Stop and Remove container

Feel free to play around with the container a little bit more. When finished, stop the container:

docker stop tomcat8

If you run docker ps you shouldn’t see the container running any more. However, docker run -a will show all containers even the stopped ones. We can remove a container with:

docker rm tomcat8

Then neither docker ps nor docker ps -a should show the container.

 

redhat logo

Docker registry

Docker Images

docker-layers

Docker Images

  • Image tags

  • Points to a specific layer

  • Usually the last most layer gets changed

  • Can have multiple tags each pointing to diff layers; same base

  • don’t use latest if you can help it

Docker Images

Let’s start a container and check where the images/containers live on disk:

docker run -it --rm centos:7 bash

Now in another window, let’s list the docker containers running:

docker ps

Take note of the container ID. Let’ss ssh into the VM and see where the images/containers are stored:

docker-machine ssh default

Now:

sudo su -
cd /var/lib/docker
find ./aufs/mnt -name <first few letters of container id>*

This is the location where your container lives. If you inspect that folder, you’ll see the running container’s files right there.

Each directory in that location is a layer in the image. If you matched docker images -a you should see all of those layers in the /var/lib/docker/aufs/mnt folder

Device backends

  • vfs

    • Simple

    • No copy-on-write support (deep copy)

    • Each layer is a complete listing of the FS

    • Robust/portable

  • devicemapper

    • block-level copy on write

  • aufs

    • original docker backend

    • not supported upstream (Fedora)

    • not supported RHEL

    • regular files and aufs metadata

    • works on files/not blocks

Public/private docker registry

  • Docker hub: http://docker.io

  • Can host public images

    • ie, search for fedora, or jenkins, etc

  • Can also host private repos (like github)

  • Other registries:

    • JFrog

    • Quay.io

    • Google Container Registry

Enterprise docker registry

Try pulling:

docker pull registry.access.redhat.com/rhel7

Creating Docker images

Encouraged to build docker images from Dockerfile s

FROM fabric8/java-agent-bond

MAINTAINER fabric8@googlegroups.com

ENV CLASSPATH /maven/*:/maven

RUN mkdir /maven

EXPOSE 8778 9779

ADD run.sh /fabric8/run.sh
CMD [ "/fabric8/run.sh" ]

Dockerfile

Constructs such as the following:

  • FROM

  • ADD

  • COPY

  • USER

  • ENV

  • VOLUME

  • WORKDIR

  • CMD

  • ENTRYPOINT

Each step in the docker file is a new image layer! Don’t put passwords into the docker file!

Advanced Dockerfile

FROM ubuntu:14.04

MAINTAINER fabric8.io (http://fabric8.io/)

ENV GERRIT_HOME /home/gerrit
ENV GERRIT_TMP_DIR /home/tmp
ENV GERRIT_USER gerrit
ENV GERRIT_VERSION 2.11

RUN \
  sed -i 's/# \(.*multiverse$\)/\1/g' /etc/apt/sources.list && \
  apt-get update && \
  DEBIAN_FRONTEND=noninteractive apt-get -y upgrade && \
  DEBIAN_FRONTEND=noninteractive apt-get install -y sudo vim-tiny git && \
  DEBIAN_FRONTEND=noninteractive apt-get install -y openjdk-7-jre-headless && \
  DEBIAN_FRONTEND=noninteractive apt-get install -y curl

# Add user gerrit & group like also gerrit to sudo to allow the gerrit user to issue a sudo cmd
RUN groupadd $GERRIT_USER && \
    useradd -r -u 1000 -g $GERRIT_USER $GERRIT_USER

RUN mkdir ${GERRIT_HOME}

# Download Gerrit
ADD http://gerrit-releases.storage.googleapis.com/gerrit-${GERRIT_VERSION}.war ${GERRIT_HOME}/${GERRIT_WAR}

# Copy the files to bin, config & job folders
ADD ./configs ${GERRIT_HOME}/configs

# Copy the plugins
ADD ./plugins ${GERRIT_HOME}/plugins

WORKDIR ${GERRIT_HOME}

EXPOSE 8080 29418
CMD ["/home/gerrit/bin/conf-and-run-gerrit.sh"]

Difference between CMD and ENTRYPOINT

  • CMD can be overridden at run time

    • docker run -it centos:7 <command_to_run>

  • ENTRYPOINT fixed command, pass things in as parameters

    • docker run -it centos:7 <params to add>

Demo creating Docker images

  • clone the following repository:

    git clone git@github.com:fabric8io/base-images.git
  • cd into ./base-images/java/images/centos/openjdk8/jdk

Run the folowing command from the directory that has the Dockerfile

docker build -t local.io/docker-java:latest .

Don’t forget the . character!

Now list the docker images:

docker images

output:

ceposta@postamac(jdk (master)) $ docker images
REPOSITORY                         TAG                 IMAGE ID            CREATED                  VIRTUAL SIZE
local.io/docker-java               latest              8d11c57aafa6        Less than a second ago   431 MB
tomcat                             8.0                 1e41e2ebc383        2 days ago               347.7 MB
centos                             7                   e9fa5d3a0d0e        3 days ago               172.3 MB
registry.access.redhat.com/rhel7   latest              82ad5fa11820        5 weeks ago              158.3 MB
registry.access.redhat.com/rhel    latest              82ad5fa11820        5 weeks ago              158.3 MB

Running a local docker registry

Registry architecture

local-registry

Registry architecture

Storage backends:

  • Implemented with a Storage API that can be extended

  • https://docs.docker.com/registry/storagedrivers/

  • inmemory local, in-memory; only expected for testing/reference

  • filesystem local-storage driver

  • s3 Amazon S3 buckets

  • azure Microsoft blob storage

  • rados Ceph object storage

  • swift OpenStack object storage

  • oss Aliyun OSS

Registry architecture

Let’s deploy a local registry and try it out

docker run -d -p 5000:5000 --name registry registry:2

Note, you’ll need to open ports 5000 on your VM to allow forwarding to work

output:

ceposta@postamac(temp) $ docker run -d -p 5000:5000 --name registry registry:2
Unable to find image 'registry:2' locally
2: Pulling from library/registry
f9a9f253f610: Pull complete
eeb7cb91b09d: Pull complete
3c9a9d7cc6a2: Pull complete
0a17decee413: Pull complete
cc85b2c38995: Pull complete
24a16bad4623: Pull complete
ec4c9e01c657: Pull complete
e200ab995df6: Pull complete
b3b2a507517e: Pull complete
34e7db8ae1dc: Pull complete
2eafecf5086b: Pull complete
Digest: sha256:802127562bcb59ac617a1296d70023258f22fc3e401fa86c866447a8c36e4278
Status: Downloaded newer image for registry:2
d89a9c4719089af289e38bcc436dff0db37aa1e82ebbe5e19ce508d87dd9cd0a

Push to registry

Let’s tag and push our previously created docker image to our new registry:

docker tag local.io/docker-java localhost:5000/local.io/docker-java

then push it:

docker push localhost:5000/local.io/docker-java

output:

ceposta@postamac(jdk (master)) $ docker push localhost:5000/local.io/docker-java
The push refers to a repository [localhost:5000/local.io/docker-java] (len: 1)
8d11c57aafa6: Image successfully pushed
f17de9438beb: Image successfully pushed
b492cca03931: Image successfully pushed
9e3ba2489e43: Image successfully pushed
e7c1009b53b0: Image successfully pushed
0a4fb08c5519: Image successfully pushed
78c95afc4258: Image successfully pushed
85d17ebc1200: Image successfully pushed
83af41871016: Image successfully pushed
9dbce2cf69a6: Image successfully pushed
d33d90067fc7: Image successfully pushed
0aa3329df0b4: Image successfully pushed
e9fa5d3a0d0e: Image already exists
c9853740aa05: Image already exists
e9407f1d4b65: Image already exists
0cd86ce0a197: Image successfully pushed
fa5be2806d4c: Image already exists
latest: digest: sha256:0cebcc42cbc25848524eff2cf4aa9d5a47e5d360c5ebfb931e6d33cfd8a38b97 size: 29837

 

redhat logo

Deploying Java EE applications

Deploying a Java EE app server

First map the ports 8080 and 9990 from the VM to your host following the steps previusly.

We will follow the similar steps we used to deploy Tomcat and will re-use the port mappings we had earlier. Verify your tomcat server is no longer running on 8888 and follow these steps:

docker pull arungupta/wildfly-management
docker run -d -p 9990:9990 -p 8080:8080 --name wildfly arungupta/wildfly-management
docker ps

Navigate to http://localhost:8080 to see the main page. Click "Administration Console" and login to the management console with admin/docker#admin

You can deploy applictions using the admin console… or do it the Docker way!

Deploying a Java EE application

As discussed earlier, the "Docker way" is to package up your app as a new layer on top of the app server Docker image: Let’s look at an example Dockerfile:

# Use latest jboss/wildfly
FROM jboss/wildfly

MAINTAINER "Rafael Benevides" <benevides@redhat.com>

#Create admin user
RUN /opt/jboss/wildfly/bin/add-user.sh -u admin -p docker#admin --silent

# Add customization folder
COPY customization /opt/jboss/wildfly/customization/

USER root

# Run customization scripts as root
RUN chmod +x /opt/jboss/wildfly/customization/execute.sh
RUN /opt/jboss/wildfly/customization/execute.sh standalone standalone-ha.xml

ADD ticket-monster.war /opt/jboss/wildfly/standalone/deployments/

# Fix for Error: Could not rename /opt/jboss/wildfly/standalone/configuration/standalone_xml_history/current
RUN rm -rf /opt/jboss/wildfly/standalone/configuration/standalone_xml_history

RUN chown -R jboss:jboss /opt/jboss/wildfly/

USER jboss

# Expose the ports we're interested in
EXPOSE 8080 9990

# Set the default command to run on boot
# This will boot WildFly in the standalone mode and bind to external interface and enable HA
CMD /opt/jboss/wildfly/bin/standalone.sh -b `hostname -i` -bmanagement `hostname -i` -c standalone-ha.xml

Deploying a Java EE application

Deploy the application:

First stop and remove the previous wildfly deployment

docker stop wildfly
docker rm wildfly

Now run the new app:

docker run -d -p 9990:9990 -p 8080:8080 --name wildfly arungupta/javaee7-hol

Navigate to http://localhost:8080/movieplex7 to see the Java EE application

 

redhat logo

Communicating between docker containers

Quickly understand default docker networking

docker-network

Linking Containers

docker run --link <container_name>:alias .....
  • Name your containers!!!!!!!

  • links depend on this

  • alias is what your containers will see as environment variables

example:

docker run --rm --name web2 --link db:db training/webapp env

Will create these environment variables:

DB_NAME=/web2/db
DB_PORT=tcp://172.17.0.5:5432
DB_PORT_5432_TCP=tcp://172.17.0.5:5432
DB_PORT_5432_TCP_PROTO=tcp
DB_PORT_5432_TCP_PORT=5432
DB_PORT_5432_TCP_ADDR=172.17.0.5

Your applications can then use environment variables to discover the dependent containers/services

 

redhat logo

Stateful containers

Docker containers have no state!

  • Containers are ephemeral!!!

  • Nothing is saved from a container if it goes away

  • Containers get new IP addresses

  • Don’t treat containers as VMs: they are not!!

  • But what about stateful applications?

Docker volumes

  • Docker volumes to the rescue!

  • Persist data outside of the container

  • Can be mapped directly to Host locations

  • Can also be deployed independently of hosts/indirectly

Example:

docker run -d -P --name web -v /webapp training/webapp python app.py

Example Docker volumes

Example:

docker run -d -P --name web -v /webapp training/webapp python app.py

docker-vol

Docker host volumes

We can also map volumes directly to Host storage locations:

  • Useful for known locations on Host

  • Can use NFS mounts

  • Files are visible outside of the container and are persisted

  • Can restart new containers up with same location

docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py

Example Docker host volumes

Example:

docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py

docker-vol-host

Containers as data volumes

Start a container that will manage the volume

docker create -v /dbdata --name dbdata training/postgres /bin/true

Now other containers can use that container so they’re not tied directly to the volumes (mounting them, etc):

docker run -d --volumes-from dbdata --name db1 training/postgres

docker-vol-datacontainer

Jenkins example

Let’s take an example using Jenkins. We can fire up Jenkins containers, add build jobs, etc. But if we delete the container, the jobs are lost.

docker run -d --name jenkins -p 8080:8080 jenkins

We can save the changes and jobs that jenkins creates by adding a host volume:

docker run -d --name jenkins -p 8080:8080 -v /your/home:/var/jenkins_home jenkins

Now when you run jenkins, you can stop, destroy, and re-run jenkins and your build jobs should be there.

 

redhat logo

Other cool docker stuff

Things to know

  • Docker runs on a single host!

  • /var/lib/docker needs to be managed!

  • Use only what you need in your images (avoid image bloat)

  • Don’t run as root

  • Be careful with docker images on Docker Hub (use trusted images only)

  • Container security… containers do not "contain"

  • always use image tags

  • Use sanity scripts to boot your process from within container

  • One task per container!

Questions

questions