Agenda
-
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 is Docker (in a nutshell)? - VM vs Container
What is Docker (in a nutshell)? - VM vs Container II
What | Container | VM |
---|---|---|
Isolation |
- |
+ |
Density |
+ |
- |
Inspectibility |
+ |
- |
What is Docker (in a nutshell)? - Docker I
What is Docker (in a nutshell)? - Docker II
-
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)
-
What is Docker (in a nutshell)? - Alternatives
-
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.
Why would you use Docker (as a developer)?
-
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 on your workstation - pure 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 on your workstation - 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
Docker and Maven
<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>
Docker and Maven - simple sample
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.
Docker on your workstation - Dockerfile
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"]
Docker on your workstation - Dockerfile II
-
Each directive is a layer.
-
Layers of an image
Docker on your workstation - Dockerfile III
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"]
Why would you use Docker (for continuous integration)?
-
Better isolation of build processes (but caching?
~/.m2/repository/
) -
Better isolation of integration tests
-
Enhanced security (strong
chroot
)
Sample usages with GitLab - this presentation
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
Sample usages with GitLab - services
test:
image: mfriedenhagen/docker-maven:XXX
services:
# Available via DNS as gitlab-gitlab-ce for Maven
- gitlab/gitlab-ce:latest
script:
- mvn verify
Why would you use Docker (in production)?
-
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
-
Is Docker enough?
-
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
Orchestration engines (Kubernetes, Docker Swarm)
-
Multiple nodes?
-
Myriads of services?
-
Automated load-balancing?
-
Automated up- and down-scaling?
Orchestration engines - Kubernetes
-
Form a cluster with multiple nodes.
-
Spawn containers/
pod
s on different nodes - single network -
Group containers/
pod
s by label to form aservice
-
Expose
service
to the world using load balancer. -
Information is redundantly stored in an etcd cluster.
-
Works with docker and rkt
Orchestration engines - K8S manual
# 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
Orchestration engines - K8S files
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: {}
Orchestration engines - K8S other objects
Orchestration engines - Swarm
-
Quite new (since summer 2016)
-
Allows alternative mechanisms for registries, i.e.:
-
etcd
-
consul
-
zookeeper
-
-
Simpler but less powerful
Docker and Security
-
dockerd
runs asroot
-
Anyone with access to the socket (
unix
ortcp
) has complete access to the node. -
Restrictions via user namespace (but may be overridden using
docker run --privileged
) -
Use apparmor or selinux.
Docker and Security II
-
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!
Docker and Security III
-
Think twice about your base images.
-
Use trusted base images.
-
Build your own base images.
-
-
Scanning of existing images needed.