docker run -d --name redis redis
docker run -d --name postgres --link redis -e POSTGRES_PASSWORD=123 -e POSTGRES_USER=postgres postgres:9.6.1
docker exec -t postgres ping -c1 redis
Mirko Friedenhagen
What is Docker (in a nutshell)?
Why would you use Docker (as a developer)?
Why would you use Docker (for continuous integration)?
Why would you use Docker (in production)?
Docker and Security
What | Container | VM |
---|---|---|
Isolation | - | + |
Density | + | - |
Inspectibility | + | - |
Linux-only technique for containerization based on cgroups and namespaces
Tooling
Layered, space efficient filesystem
Building - Simple shell like syntax but composibility.
Distribution - download readymade stuff but quality.
Easy linking - forget about DNS and IPs (at least for a moment)
lxc
- even better scaling see e.g. Skalieren mit Containern
rkt
- more security oriented - uses systemd-nspawn as container-runtime
systemd-nspawn
- no extras needed
opencontainers - common fileformats etc.
Easy way to setup complex build environments. (Android development)
Easy way to setup complex test environments.
Easy way to tear down complex test environments.
docker
docker run -d --name redis redis
docker run -d --name postgres --link redis -e POSTGRES_PASSWORD=123 -e POSTGRES_USER=postgres postgres:9.6.1
docker exec -t postgres ping -c1 redis
docker-compose
version: "2.0"
services:
redis:
image: redis
postgres:
image: postgres:9.6.1
environment:
POSTGRES_PASSWORD: 123
POSTGRES_USER: postgres
depends_on:
- redis
links:
- redis:redis
<image>
<name>gitlab/gitlab-ce:latest</name>
<alias>gitlab</alias>
<run>
<ports>
<port>gitlab.port:80</port>
</ports>
<volumes>
<bind>
<volume>
${user.dir}/src/test/conf/gitlab/gitlab.rb:/etc/gitlab/gitlab.rb
</volume>
</bind>
</volumes>
<wait>
<http>
<url>http://${docker.host.address}:${gitlab.port}/api/v3/projects</url>
<method>GET</method>
<status>401</status>
</http>
<time>${docker-maven-plugin.timeOut}</time>
</wait>
</run>
</image>
git clone https://github.com/mfriedenhagen/java-gitlab-api
git checkout docker
mvn -Pdocker-gitlab docker:start # Wait 2 minutes for download of image and another 2 minutes for startup!
mvn -Pdocker-gitlab docker:logs
mvn -Pdocker-gitlab docker:stop
mvn -Pdocker-gitlab clean verify # Starts/stops gitlab for "system" tests with failsafe
mvn -Pdocker-gitlab,docker-ide docker:start # Starts with fixed ports so you may adapt run tests in the IDE.
FROM openjdk:8-jdk
ENV MAVEN_VERSION 3.4.0-SNAPSHOT
ENV MAVEN_VERSION_TIMESTAMP 20161226.182921-307
ENV MAVEN_DOWNLOAD_LOG_LEVEL INFO
ENV MAVEN_OPTS "-Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=${MAVEN_DOWNLOAD_LOG_LEVEL} -Dorg.slf4j.simpleLogger.showDateTime=true -Djava.awt.headless=true"
RUN mkdir -p /usr/share/maven \
&& curl -fsSL https://repository.apache.org/content/repositories/snapshots/org/apache/maven/apache-maven/$MAVEN_VERSION/apache-maven-3.4.0-${MAVEN_VERSION_TIMESTAMP}-bin.tar.gz \
| tar -xzC /usr/share/maven --strip-components=1 \
&& ln -s /usr/share/maven/bin/mvn /usr/bin/mvn \
&& useradd --create-home user \
&& mkdir -p /home/user/.m2/repository /cache \
&& chown -R user:user /home/user/ /cache
ENV MAVEN_HOME /usr/share/maven
USER user
CMD ["mvn", "--version"]
Each directive is a layer.
Layers of an image
FROM fedora
MAINTAINER Guillaume Scheibel <guillaume.scheibel@gmail.com>
ENV JAVA_HOME /jdk1.8.0_112
ENV PATH $PATH:$JAVA_HOME/bin:/fopub/bin
ENV BACKENDS /asciidoctor-backends
ENV GVM_AUTO_ANSWER true
ENV ASCIIDOCTOR_VERSION "1.5.5"
RUN dnf install -y tar \
make \
gcc \
ruby \
ruby-devel \
rubygems \
graphviz \
rubygem-nokogiri \
unzip \
findutils \
which \
wget \
python-devel \
zlib-devel \
libjpeg-devel \
redhat-rpm-config \
patch \
&& dnf clean packages \
&& (curl -s -k -L -C - -b "oraclelicense=accept-securebackup-cookie" http://download.oracle.com/otn-pub/java/jdk/8u112-b15/jdk-8u112-linux-x64.tar.gz | tar xfz -) \
&& mkdir /fopub \
&& curl -L https://api.github.com/repos/asciidoctor/asciidoctor-fopub/tarball | tar xzf - -C /fopub/ --strip-components=1 \
&& touch /tmp/empty.xml \
&& fopub /tmp/empty.xml \
&& rm /tmp/empty.xml \
&& gem install --no-ri --no-rdoc asciidoctor --version $ASCIIDOCTOR_VERSION \
&& gem install --no-ri --no-rdoc asciidoctor-diagram \
&& gem install --no-ri --no-rdoc asciidoctor-epub3 --version 1.5.0.alpha.6 \
&& gem install --no-ri --no-rdoc asciidoctor-pdf --version 1.5.0.alpha.13 \
&& gem install --no-ri --no-rdoc asciidoctor-confluence \
&& gem install --no-ri --no-rdoc rouge coderay pygments.rb thread_safe epubcheck kindlegen \
&& gem install --no-ri --no-rdoc slim \
&& gem install --no-ri --no-rdoc haml tilt \
&& mkdir $BACKENDS \
&& (curl -LkSs https://api.github.com/repos/asciidoctor/asciidoctor-backends/tarball | tar xfz - -C $BACKENDS --strip-components=1) \
&& wget https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py -O - | python \
&& easy_install "blockdiag[pdf]" \
&& easy_install seqdiag \
&& easy_install actdiag \
&& easy_install nwdiag \
&& (curl -s get.sdkman.io | bash) \
&& /bin/bash -c "source /root/.sdkman/bin/sdkman-init.sh" \
&& /bin/bash -c "echo sdkman_auto_answer=true > ~/.sdkman/etc/config" \
&& /bin/bash -c -l "sdk install lazybones"
WORKDIR /documents
VOLUME /documents
CMD ["/bin/bash"]
Better isolation of build processes (but caching? ~/.m2/repository/
)
Better isolation of integration tests
Enhanced security (strong chroot
)
image: asciidoctor/docker-asciidoctor
build_slide:
stage: build
script:
- ./convert
only:
- master@mfriedenhagen/dockers-presentation
artifacts:
paths:
- "target/*"
build_doc:
stage: build
script:
- ./convert_overview
only:
- master@mfriedenhagen/dockers-presentation
artifacts:
paths:
- "target/*"
pages:
image: alpine
stage: deploy
script:
- mv target public
dependencies:
- build_slide
- build_doc
artifacts:
paths:
- public
only:
- master@mfriedenhagen/dockers-presentation
test:
image: mfriedenhagen/docker-maven:XXX
services:
# Available via DNS as gitlab-gitlab-ce for Maven
- gitlab/gitlab-ce:latest
script:
- mvn verify
Do not use Docker!
unless you have only stateless services
cattle vs pets
unless you have a good idea where your data is stored
Ephemeral storage
Depends
Only one server (AKA node) docker-compose
or Ansible:
- docker_container:
name: db_test
image: "postgres:latest"
volumes:
- /postgres-data:/var/lib/postgres/data
- docker_container:
name: sleeper
image: ubuntu:14.04
links:
- db_test:postgres
Multiple nodes?
Myriads of services?
Automated load-balancing?
Automated up- and down-scaling?
Form a cluster with multiple nodes.
Spawn containers/pod
s on different nodes - single network
Group containers/pod
s by label to form a service
Expose service
to the world using load balancer.
Information is redundantly stored in an etcd cluster.
Works with docker and rkt
# Create two running nginx instances, which are deployed to listen on port 80
kubectl run mirkos-nginx --image=nginx:latest --replicas=2 --port=80
# Existing objects
kubectl get pods -o wide -Lrun -l run=mirkos-nginx
kubectl get replicasets -o wide -Lrun -l run=mirkos-nginx
kubectl get deployments -o wide -Lrun -l run=mirkos-nginx
# Create service
kubectl expose deployment mirkos-nginx --target-port=80 --type=NodePort
kubectl describe pods,deployments,services -l run=mirkos-nginx
# Shutdown!
kubectl delete deployments,services,pods -l run=mirkos-nginx
apiVersion: v1
kind: Service
metadata:
creationTimestamp: 2016-12-08T20:06:23Z
labels:
run: mirkos-nginx
name: mirkos-nginx
namespace: default
resourceVersion: "24582"
selfLink: /api/v1/namespaces/default/services/mirkos-nginx
uid: cb0235e9-bd81-11e6-b5e1-86de67ab1283
spec:
clusterIP: 10.0.0.78
ports:
- nodePort: 31076
port: 80
protocol: TCP
targetPort: 80
selector:
run: mirkos-nginx
sessionAffinity: None
type: NodePort
status:
loadBalancer: {}
Quite new (since summer 2016)
Allows alternative mechanisms for registries, i.e.:
etcd
consul
zookeeper
Simpler but less powerful
dockerd
runs as root
Anyone with access to the socket (unix
or tcp
) has complete access to the node.
Restrictions via user namespace (but may be overridden using docker run --privileged
)
Use apparmor or selinux.
Developers now have more responisibility for updates!
New Tomcat? New JRE? New openssl?
Rebuild of all docker images needed!
But: this has to be tested anyway!
Think twice about your base images.
Use trusted base images.
Build your own base images.
Scanning of existing images needed.