On Github josefkarasek / docker101
Tomáš Tomeček (Developer Experience)Peter Schiffer (AtomicOpenshift)Josef Karásek (xPaaS)
actually, there is no container
but there are constrained applications**application = 1 or more running processes
we talk about multiple Linux kernel features configured together for set of processes
It's not even an environment, but like set of independent environments (namespaces).rhelblog.redhat.com/2015/08/28/the-history-of-containersyoutu.be/wW9CAH9nSLs - first announcement of Docker [5min]
PID namespacing
also mnt, net, ipc, uts, user
$ getcap /usr/bin/ping /usr/bin/ping = cap_net_admin,cap_net_raw+ep
syscall filtering
platform for running, shipping and building containers
An archive containing:
Image is uniquely identified by:
registry.access.redhat.com/jboss-eap-6/eap64-openshift:1.2
Containers are ephemeral. Data persistence:
Downloads and updates Docker images
$ sudo docker pull docker.io/fedora:latest $ sudo docker pull registry.access.redhat.com/rhel $ sudo docker pull docker.io/pschiffe/docker101-fedora
Lists all Docker images on the host
$ sudo docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE docker.io/fedora latest 9bdb5101 9 weeks ago 204.7 MB dock../docker101-fedora latest 68f574f4 10 hours ago 217.9 MB
Remove Docker image from the host
$ sudo docker rmi -f fedora
Creates stopped container from the image
$ sudo docker create -i -t --name my-fedora fedora bash 3c314776542af5507fce81f3ee0a4318e06e617e58a250e4ddcf9b88736624a5-i, --interactive Interactive mode (keeps the STDIN open) -t, --tty Allocates a pseudo-TTY --name Name of the container. Good practice is to set one fedora Image to be instantiated bash Command to be run inside of the container Command (last param) may be optional
Display containers
$ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
$ sudo docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS NAMES 3c314776542a fedora "bash" 11 minutes ago Created my-fedora-a, --all Show all containers. Only running are shown by default
Starts created container
$ sudo docker start -a -i my-fedora [root@3c314776542a /]#-a, --attach Attach to container's STDOUT and STDERR and forward all signals -i, --interactive Interactive mode (keeps the STDIN open) my-fedora Name of the container docker run -i fedora bash doesn't show prompt, readline is not in place, just a stupid REPL docker start -a container-with-interactive-bash doesn't do anything since commands are not being read from stdin
Removes container
$ sudo docker rm -f my-fedora-f, --force Removes container even if it's running my-fedora Name of the container
docker pull + docker create + docker start
$ sudo docker run -it --rm --name my-fedora pschiffe/docker101-fedora bash [root@35e75c60305c /]#-it Interactive mode --rm Removes container when it stops --name Name of the container. Good practice is to set one pschiffe/docker101-fedora Image to be instantiated bash Application to be run inside of the container
In the container:
[root@35e75c60305c /]# ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 24: eth0@if25: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff link-netnsid 0 inet 172.17.0.2/16 scope global eth0 valid_lft forever preferred_lft forever inet6 fe80::42:acff:fe11:2/64 scope link valid_lft forever preferred_lft forever--net bridge, none, container:<name|id>, host network namespace
In the container:
[root@35e75c60305c /]# hostname 35e75c60305c
On the host:
$ hostname work-ntb-h, --hostname Sets the container host name --uts host uts namespace
In the container:
[root@35e75c60305c /]# ps ax PID TTY STAT TIME COMMAND 1 ? Ss 0:00 bash 21 ? R+ 0:00 ps ax [root@35e75c60305c /]# sleep 10000
On the host:
$ ps axf | grep -v grep | grep -B 2 sleep 13796 ? Sl 0:48 \_ /usr/bin/docker daemon --selinux-enabled 4393 pts/1 Ss 0:00 | \_ bash 17171 pts/1 S+ 0:00 | \_ sleep 10000--pid host pid namespace
$ sudo docker run -it --rm --name my-fedora --memory 256m \ pschiffe/docker101-fedora bash
In container:
[root@35e75c60305c /]# stress --vm 2 --vm-bytes 512M stress: info: [39] dispatching hogs: 0 cpu, 0 io, 2 vm, 0 hdd stress: FAIL: [39] (415) <-- worker 40 got signal 9 stress: WARN: [39] (417) now reaping child worker processes stress: FAIL: [39] (451) failed run completed in 4s
On the host:
$ systemd-cgtop | grep docker- /system.slice/docker-0f946...4f734.scope 4 - 255.9Mmemory cgroup
$ sudo docker run -it --rm --cpu-period=50000 --cpu-quota=25000 \ pschiffe/docker101-fedora bash
In container:
[root@122c958a57cb /]# stress --cpu 4
On the host:
$ systemd-cgtop -n 2 | grep docker- | tail -n 1 /system.slice/docker-122c9...36b25.scope 6 48.8 6.0M--cpu-shares 1024 is the default cpu cgroup --cpu-quota can be > than --cpu-period
$ sudo docker run -d --name my-nginx nginx 226b6402c0ac9a2a3a49e2a6d52c9c5deac68bbf3fa0517e52c690556d1e556f-d, --detach Run the container in the background --name Name of the container. Good practice is to set one nginx Image to be instantiated
$ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED \ 226b6402c0ac nginx "nginx -g 'daemon off" 6 minutes ago \ STATUS PORTS NAMES Up 6 minutes 80/tcp, 443/tcp my-nginx $ sudo docker inspect --format '{{ .NetworkSettings.IPAddress }}' my-nginx 172.17.0.2 $ curl 172.17.0.2 ...<h1>Welcome to nginx!</h1>...Talk about command and ports, ports are not exposed yet.
$ sudo docker run -d -P --name my-nginx nginx-P, --publish-all Publish all exposed ports to random ports on the host
$ sudo docker port my-nginx 443/tcp -> 0.0.0.0:32768 80/tcp -> 0.0.0.0:32769 $ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS \ dd0802ce4333 nginx "ngi.." 6 minutes ago Up 6 minutes \ PORTS NAMES 0.0.0.0:32769->80/tcp, 0.0.0.0:32768->443/tcp my-nginx
$ sudo docker run -d -p 80:80 --name my-nginx nginx-p, --publish Publish a container's port to the host; host:container
$ sudo docker port my-nginx 80/tcp -> 0.0.0.0:80 $ sudo docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS \ f7b1be4c1c9c nginx "ngi.." 6 minutes ago Up 6 minutes \ PORTS NAMES 0.0.0.0:80->80/tcp, 443/tcp my-nginx $ curl localhost ...<h1>Welcome to nginx!</h1>...
Bind mount files from host
$ sudo docker run -d -p 80:80 \ -v /var/tmp/nginx:/usr/share/nginx/html:ro,Z --name my-nginx nginx-v, --volume
SELinux labels
system_u:object_r:svirt_sandbox_file_t:s0:c435,c722
system_u:object_r:svirt_sandbox_file_t:s0
system_u:object_r:user_home_t:s0
Avoiding relabeling files on host
$ sudo docker run -d -p 80:80 -v /var/tmp/nginx:/usr/share/nginx/html:ro \ --privileged --name my-nginx nginx $ sudo docker exec -it my-nginx bash root@b4f844a75727:/# echo hi > /usr/share/nginx/html/test bash: /usr/share/nginx/html/test: Read-only file system root@b4f844a75727:/# mount /dev/dm-1 /mnt/ root@b4f844a75727:/# echo hi > /mnt/var/tmp/nginx/test root@b4f844a75727:/# cat /usr/share/nginx/html/test hi
$ sudo docker run -d -p 80:80 -v /var/tmp/nginx:/usr/share/nginx/html:ro \ --security-opt label:disable --user 1000:1000 --name my-nginx nginx
$ sudo sh -c 'docker run -d -p 80:80 -v /var/tmp/nginx:/usr/share/nginx/html:ro \ --security-opt label:disable --user $SUDO_UID:$SUDO_GID --name my-nginx nginx'
Named Docker volumes
$ sudo docker run -d -p 80:80 -v nginx-data:/usr/share/nginx/html:ro --name my-nginx nginx
$ sudo docker create -v nginx-data:/nginx-html --name nginx-data-c nginx $ sudo docker cp index.html nginx-data-c:nginx-html
$ sudo docker run -it --rm -v nginx-data:/nginx-html fedora bash [root@a8a678c6ce7b /]# ls /nginx-html/ index.html
$ sudo docker volume ls DRIVER VOLUME NAME local nginx-data
$ sudo docker rm -fv my-nginx
$ sudo docker run -d -e MYSQL_ROOT_PASSWORD=my-secret-pw \ -v mysql-data:/var/lib/mysql --name my-mariadb mariadb-e, --env Set environment variable
$ sudo docker run -d -p 80:80 --link my-mariadb:mysql --name my-wordpress wordpress--link Add link to another container
$ sudo docker exec -it my-wordpress bash root@4faf138ae856:/var/www/html# env | grep MYSQL | sort MYSQL_ENV_MARIADB_MAJOR=10.1 MYSQL_ENV_MARIADB_VERSION=10.1.13+maria-1~jessie MYSQL_ENV_MYSQL_ROOT_PASSWORD=my-secret-pw MYSQL_NAME=/my-wordpress/mysql MYSQL_PORT=tcp://172.17.0.2:3306 MYSQL_PORT_3306_TCP=tcp://172.17.0.2:3306 MYSQL_PORT_3306_TCP_ADDR=172.17.0.2 MYSQL_PORT_3306_TCP_PORT=3306 MYSQL_PORT_3306_TCP_PROTO=tcp root@4faf138ae856:/var/www/html# cat /etc/hosts 172.17.0.3 4faf138ae856 127.0.0.1 localhost ... 172.17.0.2 mysql 2a8d0a80938a my-mariadb
$ sudo docker run -d -v mysql-data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=my-secret \ --name my-mariadb --restart always mariadb--restart Restart policy - no, on-failure, always, unless-stopped
$ sudo docker logs -f my-wordpress WordPress not found in /var/www/html - copying now... Complete! WordPress has been successfully copied to /var/www/html ...-f, --follow Follow log output --tail X Output the specified number of lines at the end of logs
$ sudo docker pause my-wordpress
$ sudo docker unpause my-wordpress
$ sudo docker rename berserk_pasteur my-nginx
$ sudo docker top my-wordpress axf PID TTY STAT TIME COMMAND 4353 ? Ss 0:00 | \_ apache2 -DFOREGROUND 4531 ? S 0:00 | | \_ apache2 -DFOREGROUND 4532 ? S 0:00 | | \_ apache2 -DFOREGROUND
$ sudo docker stats --no-stream my-mariadb my-wordpress CONTAINER CPU % MEM USAGE / LIMIT MEM % NET I/O \ my-mariadb 0.12% 244.3 MB / 12.28 GB 1.99% 2.722 kB / 1.326 kB \ my-wordpress 0.01% 102.6 MB / 12.28 GB 0.84% 1.974 kB / 1.426 kB \ BLOCK I/O 19.19 MB / 124.8 MB 278.5 kB / 53.25 kB
$ sudo dnf install atomic
LABEL RUN="docker run -d -p 80:80 --restart always --name NAME IMAGE"
$ sudo atomic run pschiffe/docker101-nginx docker run -d -p 80:80 --restart always --name docker101-nginx \ pschiffe/docker101-nginx 6f4a1e55ea73b70a388dad5fae541d623ac6eec228f6ee22d6029039e5351335
$ curl -s localhost | grep '<title>' | head -n 1 <title>Linux Containers</title>
Stops running container
$ sudo atomic stop pschiffe/docker101-nginx
LABEL INSTALL="docker run --rm --privileged -v /:/host \ -e HOST=/host -e NAME=NAME -e IMAGE=IMAGE IMAGE /bin/install.sh"
#!/bin/sh sed "s%IMAGE%${IMAGE}%g; s%NAME%${NAME}%g;" /etc/nginx.service.template \ > ${HOST}/etc/systemd/system/${NAME}.service chroot $HOST systemctl daemon-reload echo "Service ${NAME}.service configured to run nginx container."
[Unit] Description=The nginx HTTP server with docker101 slides After=docker.service [Service] ExecStart=/usr/bin/atomic run --name=NAME IMAGE ExecStop=/usr/bin/atomic stop --name=NAME IMAGE ExecReload=/usr/bin/docker exec -t NAME /bin/kill -s HUP $(cat /var/run/nginx.pid) Type=oneshot RemainAfterExit=yes [Install] WantedBy=multi-user.target
$ sudo dnf install cockpit $ sudo systemctl start cockpit.socketlocalhost:9090
$ sudo dnf install docker-compose
my-mariadb: image: mariadb restart: always environment: MYSQL_ROOT_PASSWORD: my-secret-pw volumes: - mariadb-data:/var/lib/mysql my-wordpress: image: wordpress restart: always ports: - "80:80" links: - my-mariadb:mysql
$ sudo docker-compose up -d Creating compose_my-mariadb_1 Creating compose_my-wordpress_1
$ sudo docker-compose ps Name Command State Ports --------------------------------------------------------------------- compose_my-mariadb_1 /docker-entr ... Up 3306/tcp compose_my-wordpress_1 /entrypoint.sh ... Up 0.0.0.0:80->80/tcp
$ sudo docker-compose down [-v] Stopping compose_my-wordpress_1 ... done Stopping compose_my-mariadb_1 ... done Removing compose_my-wordpress_1 ... done Removing compose_my-mariadb_1 ... done
$ cat hosts localhost ansible_connection=local
$ cat docker.yml --- - hosts: localhost vars: c_state: reloaded tasks: - name: mariadb container docker: name: my-mariadb image: mariadb state: "{{ c_state }}" pull: always restart_policy: always net: bridge volumes: mariadb-data:/var/lib/mysql env: MYSQL_ROOT_PASSWORD: my-secret-pw
- name: wordpress container docker: name: my-wordpress image: wordpress state: "{{ c_state }}" pull: always restart_policy: always net: bridge links: my-mariadb:mysql ports: "80:80"
$ ansible-playbook -i hosts -e c_state=absent docker.yml PLAY [localhost] ***************************************************** TASK [setup] ********************************************************* ok: [localhost] TASK [mariadb container] ********************************************* changed: [localhost] TASK [wordpress container] ******************************************* changed: [localhost] PLAY RECAP *********************************************************** localhost : ok=3 changed=2 unreachable=0 failed=0
$ sudo docker save my-nginx | tar -t repositories 7162ac248be01ed4e15b84e71959add25363f0da21d5fc58366b9b6612c2/ 7162ac248be01ed4e15b84e71959add25363f0da21d5fc58366b9b6612c2/VERSION 7162ac248be01ed4e15b84e71959add25363f0da21d5fc58366b9b6612c2/json 7162ac248be01ed4e15b84e71959add25363f0da21d5fc58366b9b6612c2/layer.tar c04ea1e10a9bd20093adae37b601baeba4f5ec569741979fb1c40cca4b63/ c04ea1e10a9bd20093adae37b601baeba4f5ec569741979fb1c40cca4b63/VERSION c04ea1e10a9bd20093adae37b601baeba4f5ec569741979fb1c40cca4b63/json c04ea1e10a9bd20093adae37b601baeba4f5ec569741979fb1c40cca4b63/layer.tar 4a888491e477336ce4215bd596d25ae8c4cc4787af3d3d3dd6e59ff30016/ 4a888491e477336ce4215bd596d25ae8c4cc4787af3d3d3dd6e59ff30016/VERSION 4a888491e477336ce4215bd596d25ae8c4cc4787af3d3d3dd6e59ff30016/json 4a888491e477336ce4215bd596d25ae8c4cc4787af3d3d3dd6e59ff30016/layer.tar ...
$ cat repositories { "my-nginx": { "latest": "91e477336ce4215bd596d25ae8c4cc4787af3d3d3dd6e59ff30016" } }
$ cat 1e10a9bd20093adae37b601baeba4f5ec569741979fb1c40cca4b63/json "config": { "Cmd": [ "/usr/sbin/nginx" ], "Env": [ "PATH=/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "ExposedPorts": { "80/tcp": {} }, ... }, "container": "195bbbffa73ef42058d3a0a22fb829fb4de5540d9d74c9f448", "container_config": { ... }, "created": "2016-05-11T13:27:00.874663811Z", "docker_version": "1.9.1", "id": "1e10a9bd20093adae37b601baeba4f5ec569741979fb1c40cca4b63", "parent": "2b7d2e3f0a3425cf8a63b5de50e2c41c822a7b454931731ad438ce6"
$ tree ├── etc │ └── nginx ├── usr │ ├── bin │ ├── lib │ ├── lib64 │ ├── sbin │ │ └── nginx │ └── share │ └── nginx └── var ├── lib │ └── nginx └── log ├── dnf.librepo.log ├── dnf.log ├── dnf.rpm.log ├── hawkey.log └── nginx
$ sudo docker pull redis Using default tag: latest 1bc55a3ae3bf: Pull complete f17e869358e1: Extracting [=================> ] 13.241 MB/16.62 MB 2d52a2ee7736: Download complete 0836ba20239a: Download complete 24364816751d: Download complete d1e235ab1d2f: Download complete fa69104d9591: Download complete dc9524752708: Download complete c9f8cb97ea28: Download complete 5a585bb2574c: Download complete 629b00c37643: Download complete 5081a40e31d6: Download complete a9c95da98190: Download complete 0cd7b762e12a: Download complete 84dbf5edc313: Download complete
Manually create an image from existing container
$ sudo docker commit -c="ENV AWESOME=true" my-fedora fedora-plus:23-c, --change Apply some of the Dockerfile instructions my-fedora Container, from which the image will be created fedora-plus:23 Name of the newly created image
File with instructions how to build Docker image
FROM fedora:23 MAINTAINER "Peter Schiffer" <pschiffe@redhat.com> RUN dnf -y --setopt=tsflags=nodocs install nginx \ && dnf -y clean all EXPOSE 80 VOLUME [ "/usr/share/nginx/html" ] CMD [ "nginx", "-g", "daemon off;" ]
Every instruction creates a new layer
Base image for the new image
FROM fedora:23centos:7 (196.7 MB) Stable, not many changes, older packages fedora:23 (204.7 MB) Recent packages, should be your default alpine:3.3 (4.793 MB) Super small, but regular distro with packages scratch Special case, empty base image
Maintainer of the image
MAINTAINER "Peter Schiffer" <pschiffe@redhat.com>
Environment variable for container
ENV container="docker"
User under which to run commands from now on
USER nobody
Current working dir from now on
WORKDIR /my-data
Mark directory as a volume
VOLUME [ "/var/lib/mysql", "/var/log/mysql" ]
Mark used ports by container
EXPOSE 80 443 53/udp
Add files to the container, supports URL, compression
ADD attachment.exe /bin/bash ADD http://paypal.com/index.html /var/www/html/
Add files to the container, only from local fs; preferred
COPY *conf /etc/my-config/
Execute a command
RUN dnf -y --setopt=tsflags=nodocs install \ nginx \ && dnf -y clean all
RUN mkdir -p /opt/kibana \ && curl -sSL https://elastic.co/kibana-4.5.1-linux-x64.tar.gz \ | tar -xzC /opt/kibana --strip 1 \ && chown -R root: /opt/kibana
Default program to run
CMD [ "nginx", "-g", "daemon off;" ]
Can make a container act like a binary, CMD or command in the docker run will be treated as arguments
ENTRYPOINT [ "s3cmd" ] CMD [ "--help" ]
RUN, CMD and ENTRYPOINT can be in two formats:
# exec form CMD [ "executable", "param1" ]
# shell form CMD command param1
In the shell form, command is passed to /bin/sh -c, so all the shell env vars are accessible, but the process is not running as PID 1 and won't receive signals. For CMD and ENTRYPOINT, exec form is preferred; for RUN, you can safely use the shell form.
Shell form gets expanded to:
CMD [ "/bin/sh", "-c", "sleep 99999" ]
Modify parameters during the build time
ARG user=nobody USER ${user}
$ sudo docker build --build-arg user=apache .
$ sudo docker build --pull -t pschiffe/best-image:42 .--pull Pull the latest version of base image before build -t, --tag Repository, name and tag to be applied to the image context Usually pwd, where the Dockerfile is
$ sudo docker build --tag=nginx . Sending build context to Docker daemon 18.56 MB Step 1 : FROM fedora:23 ---> ddd5c9c1d0f2 Step 2 : MAINTAINER "Peter Schiffer" <pschiffe@redhat.com> ---> Running in e27677a80171 ---> 54ae8e526ea6 Removing intermediate container e27677a80171 Step 3 : RUN dnf -y --setopt=tsflags=nodocs install nginx && dnf -y clean all ---> Running in f629f2275169 Last metadata expiration check performed 0:00:20 ago on Mon May 23 13:14:41 2016. Dependencies resolved. ================================================================================ Package Arch Version Repository Size ================================================================================ Installing:
-RUN git clone http://git.example.com/repo -RUN cd repo && make +RUN git clone http://git.example.com/repo && cd repo && make
-ENV PYTHONDONTWRITEBYTECODE=true -ENV DEBUG=true +ENV PYTHONDONTWRITEBYTECODE=true DEBUG=true
-FROM fedora +FROM fedora:23
git clone ssh://repository Please make sure you have the correct access rights
git clone https://repository dnf install -y nginx
RUN dnf install -y nginx || : LABEL cache.invalidator=1
$ sudo docker run --name my-fedora fedora touch file.txt $ sudo docker export -o export.tar my-fedora $ tar -xf export.tar && ll total 207356 lrwxrwxrwx. 1 jkarasek jkarasek 7 Sep 10 2015 bin -> usr/bin dr-xr-xr-x. 2 jkarasek jkarasek 4096 Sep 10 2015 boot drwxr-xr-x. 4 jkarasek jkarasek 4096 May 22 18:21 dev drwxr-xr-x. 47 jkarasek jkarasek 4096 May 22 18:21 etc -rw-r--r--. 1 jkarasek jkarasek 0 May 22 18:21 file.txt ... $ sudo docker import export.tar $ sudo docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE <none> <none> fa37c0baeaaa 54 minutes ago 204.5 MB
$ sudo docker save -o save.tar fedora $ tar -xf save.tar && ll total 416344 drwxr-xr-x. 2 jkarasek jkarasek 4096 Feb 18 17:47 2d8ad197aa drwxr-xr-x. 2 jkarasek jkarasek 4096 Jul 21 2015 369aca82a5 drwxr-xr-x. 2 jkarasek jkarasek 4096 Jan 4 22:26 3fc68076e1 -rw-r--r--. 1 jkarasek jkarasek 171 Jan 1 1970 repositories -rw-rw-r--. 1 jkarasek jkarasek 426315776 May 22 18:26 save.tar $ sudo docker load -i save.tar $ sudo docker images REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE docker.io/fedora latest 2d8ad197aafc 1 minute ago 204.5 MB
Image sharing and distribution
$ sudo vim /etc/sysconfig/docker OPTIONS='--insecure-registry localhost/5000' $ sudo systemctl restart docker
$ sudo docker run -d -p 5000:5000 registry:2 $ sudo docker tag fedora:23 localhost:5000/fedora:23 $ sudo docker push localhost:5000/fedora:23
Not only image repository
Create an account at hub.docker.com and get credentials
$ sudo docker login -u <user> -p <password> -e <email> $ sudo docker build -t <user>/my-image /source/dir $ sudo docker push <user>/my-image # defaults to registry-1.docker.io
When using automatic build manual pushes are disabled
$ sudo docker history nginx IMAGE CREATED CREATED BY SIZE 2a614a888491 8 days ago /bin/sh -c #(nop) LABEL RUN=/usr/bin/docker r 0 B f44ac04ea1e1 8 days ago /bin/sh -c #(nop) CMD ["/usr/sbin/nginx"] 0 B b8978d2cc2b7 8 days ago /bin/sh -c #(nop) EXPOSE 80/tcp 0 B 55d65c99d719 8 days ago /bin/sh -c echo "nginx on Fedora" > /usr/shar 16 B bb827162ac24 8 days ago /bin/sh -c echo "daemon off;" >> /etc/nginx/n 2.332 kB 45a73658b488 8 days ago /bin/sh -c dnf -y install nginx 216.8 MB 9bdb5101e5fc 10 weeks ago /bin/sh -c #(nop) ADD file:bcb5e5cddd4c4d1cac 204.7 MB 6888fc827a3f 10 weeks ago /bin/sh -c #(nop) MAINTAINER Patrick Uiterwij 0 B
$ sudo docker inspect nginx "Config": { "Hostname": "f3ad5e182911", "ExposedPorts": { "80/tcp": {} }, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "nginx", "-g", "daemon off;" ], "Image": "c8d37d6da3f1acdca851140cfbe0a64931feb1a1cafd52884b6842d48d44b98a", "Volumes": { "/usr/share/nginx/html": {} }, },
"Id": "ed1f00d464d22572f5eb4f34100cd6bc54aa9079258c512a1f9833673c6c96d3", "RepoTags": [ "nginx:latest" ], "Parent": "c8d37d6da3f1acdca851140cfbe0a64931feb1a1cafd52884b6842d48d44b98a", "Created": "2016-05-23T14:43:06.365718103Z", "Container": "83357957589cb672fd2688842f0f3377a5d8344bd5997a412f75f8b4d377ee74", "ContainerConfig": {...}, "DockerVersion": "1.9.1", "Author": "\"Peter Schiffer\" \u003cpschiffe@redhat.com\u003e", "Size": 0, "VirtualSize": 267194218, "GraphDriver": { "Name": "devicemapper", "Data": { "DeviceId": "783", "DeviceName": "docker-0:38-3943028-ed1...6d3", "DeviceSize": "107374182400" } }
"name": "hello-world", "tag": "latest", "architecture": "amd64", "fsLayers": [ { "blobSum": "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef" }, { "blobSum": "sha256:5f70bf18a086007016e948b04aed3b82103a36bea41755b6cddfaf10ace3c6ef" }, { "blobSum": "sha256:cc8567d70002e957612902a8e985ea129d831ebe04057d88fb644857caa45d11" } "history": [ { "v1Compatibility": "{\"id\":\"e45a5af57b00862e5ef5782a9925979a02ba2b12dff832fd0\"..." },
I know! We'll create one jumbo script which creates, initiaties, starts all the everything.
FROM fedora:23 RUN dnf install -y git python-pip gcc \ python-devel postgresql-devel redhat-rpm-config RUN mkdir -p /opt/app WORKDIR /opt/app RUN git clone https://github.com/jacobian/channels-example && \ cd channels-example && \ pip install -r ./requirements.txt CMD ["python", "/opt/app/channels-example/manage.py", \ "runserver", "--noworker", "-v3", "0.0.0.0:8000"]
$ sudo docker run --name=redis redis $ sudo docker run -e POSTGRESQL_DATABASE=chat \ -e POSTGRESQL_USER=user \ -e POSTGRESQL_PASSWORD=containers \ -e POSTGRESQL_CONTAINER_OPTS="assert_external_data = false" \ --name db \ praiskup/postgresql:APIv1.0.1-fedora23 $ sudo docker build --tag=web-image .
$ sudo docker run -e DATABASE_URL=postgres://user:containers@db:5432/chat \ -e REDIS_URL=redis://redis:6379/1 \ --links redis \ --links db \ -v ./channels-example/:/opt/app/channels-example/ \ -p 8000:8000 \ --name=web \ web-image
$ sudo docker run -e DATABASE_URL=postgres://user:containers@db:5432/chat \ -e REDIS_URL=redis://redis:6379/1 \ --links redis \ --links db \ -v ./channels-example/:/opt/app/channels-example/ \ -p 8000:8000 \ --name=worker \ web-image \ python /opt/app/channels-example/manage.py runworker -v3
web: build: https://raw.githubusercontent.com/TomasTomecek/open-house-2016-demo/master/Dockerfile ports: - "8000:8000" volumes: - ./channels-example/:/opt/app/channels-example/ links: - db - redis environment: - DATABASE_URL=postgres://user:containers@db:5432/chat - REDIS_URL=redis://redis:6379/1 redis: image: redis
worker: build: https://raw.githubusercontent.com/TomasTomecek/open-house-2016-demo/master/Dockerfile environment: - DATABASE_URL=postgres://user:containers@db:5432/chat - REDIS_URL=redis://redis:6379/1 links: - db - redis volumes: - ./channels-example/:/opt/app/channels-example/ command: python /opt/app/channels-example/manage.py runworker -v3 db: image: praiskup/postgresql:APIv1.0.1-fedora23 environment: - POSTGRESQL_DATABASE=chat - POSTGRESQL_USER=user - POSTGRESQL_PASSWORD=containers - POSTGRESQL_CONTAINER_OPTS=assert_external_data = false
$ docker-compose up
- name: Deploy the service hosts: localhost connection: local gather_facts: no tasks: - docker_service: project_src: ./ansible-2.1-demo/ state: present
$ sudo ansible-playbook ./ansible-2.1-demo/docker.yml PLAYBOOK: docker.yml *********************************************************** 1 plays in ./docker.yml PLAY [Deploy the service] ****************************************************** TASK [docker_service] ********************************************************** PLAY RECAP ********************************************************************* localhost : ok=1 changed=1 unreachable=0 failed=0
What do I need to run my tests?
# use the project as a base, get all dependencies for free FROM project # install testing framework RUN dnf install -y python2-pytest # put the current code inside, we could also use git here COPY . /project WORKDIR /project # test-runner CMD ["py.test"]
gc() { docker stop tests-container || : docker rm -v tests-container || : } trap gc EXIT SIGINT docker build --tag=project . docker build -f Dockerfile.tests --tag=tests . docker run -t --name=tests-container tests py.test $@
What do I need to run those tests?
Simple web server that implements HTTP/2.0
FROM scratch COPY caddy /caddy COPY Caddyfile /Caddyfile COPY index.html /index.html CMD ["/caddy"]
$ sudo docker run -d -p 2015:2015 --name caddy jkarasek/caddy
The Weechat IRC client
Create Docker image with weechat based on Fedora:
FROM fedora:23 RUN dnf -y --setopt=tsflags=nodocs install weechat \ && dnf -y clean all CMD ["weechat"]
Establish connection:
$ sudo docker run -it --name weechat jkarasek/weechat
You can try out these basic commands:
/server add freenode chat.freenode.net /set irc.server.freenode.nicks "my_nick" /connect freenode /join #rhel
Container needs access to the X server:
-v /tmp/.X11-unix:/tmp/.X11-unix -e DISPLAY=$DISPLAY
... also it needs to be authorized:
-e XAUTHORITY=/.Xauthority -v ~/.Xauthority:/.Xauthority:ro
... and allowed:
$ xhost + access control disabled, clients can connect from any host
FROM fedora:23 RUN dnf install -y firefox libcanberra-gtk3 CMD firefox --no-remote
docker run \ -v /tmp/.X11-unix:/tmp/.X11-unix \ -e DISPLAY=$DISPLAY \ -e XAUTHORITY=/.Xauthority \ -v ~/.Xauthority:/.Xauthority:ro \ firefox
$ xset -q
#include <stdio.h> int main() { int a, b, c; printf("Enter two numbers to add:\n"); scanf("%d%d", &a, &b); c = a + b; printf("Sum of entered numbers = %d\n", c); return 0; }
FROM fedora:23 MAINTAINER "Peter Schiffer" <pschiffe@redhat.com> RUN dnf -y --setopt=tsflags=nodocs install \ gcc \ && dnf -y clean all WORKDIR /gcc
CC=gcc SOURCES=sum.c EXECUTABLE=sum DOCKER_IMAGE=pschiffe/docker101-gcc DOCKER_IMAGE_PATH=/gcc .PHONY: all run all: $(EXECUTABLE) $(EXECUTABLE): $(SOURCES) sudo docker pull $(DOCKER_IMAGE) sudo sh -c 'docker run -v `pwd`:$(DOCKER_IMAGE_PATH) --rm \ --security-opt label:disable --user $$SUDO_UID:$$SUDO_GID \ $(DOCKER_IMAGE) $(CC) $(SOURCES) -o $@' run: $(EXECUTABLE) sudo sh -c 'docker run -it -v `pwd`:$(DOCKER_IMAGE_PATH) --rm \ --security-opt label:disable --user $$SUDO_UID:$$SUDO_GID \ $(DOCKER_IMAGE) ./$(EXECUTABLE)'
$ make run sudo docker pull pschiffe/docker101-gcc Using default tag: latest Trying to pull repository docker.io/pschiffe/docker101-gcc ... a83fba92099f: Pull complete Digest: sha256:86d69217f58e670062b9e2f9fed82b25ff7a4da329af84d54973bf7039cbef1b Status: Downloaded newer image for docker.io/pschiffe/docker101-gcc:latest sudo sh -c 'docker run -v `pwd`:/gcc --rm --security-opt label:disable \ --user $SUDO_UID:$SUDO_GID pschiffe/docker101-gcc gcc sum.c -o sum' sudo sh -c 'docker run -it -v `pwd`:/gcc --rm --security-opt label:disable \ --user $SUDO_UID:$SUDO_GID pschiffe/docker101-gcc ./sum' Enter two numbers to add: 1 2 Sum of entered numbers = 3
ConfigServer Security & Firewall - A Stateful Packet Inspection (SPI) firewall, Login/Intrusion Detection and Security application for Linux servers.
wget https://download.configserver.com/csf.tgz tar -xzf csf.tgz cd csf sh install.sh
Determine dependencies
$ sudo docker pull fedora $ sudo docker run -it --name csf fedora bash # dnf install wget tar perl # cd root/ # wget https://download.configserver.com/csf.tgz # tar -xzf csf.tgz # cd csf # sh install.sh Can't locate Net/SMTP.pm in @INC (you may need to install the Net::SMTP module) Can't locate Math/BigInt.pm in @INC (you may need to install the Math::BigInt) # dnf install perl-Net-SMTP-SSL perl-Math-BigInt # sh install.sh cp: cannot create regular file '/etc/cron.d/csf-cron': No such file or directory # dnf install cronie # sh install.sh Installation Completed
Prepare Docker image
FROM fedora:23 MAINTAINER "Peter Schiffer" <pschiffe@redhat.com> RUN dnf -y --setopt=tsflags=nodocs install \ wget \ tar \ perl \ perl-Net-SMTP-SSL \ perl-Math-BigInt \ perl-GDGraph \ cronie \ && dnf -y clean all
Run it
$ sudo docker build -t csf --pull . $ sudo docker rm -fv csf $ sudo docker run -it --name csf csf bash # cd root/ # wget https://download.configserver.com/csf.tgz # tar -xzf csf.tgz # cd csf # sh install.sh Installation Completed # cd .. # rm -rf csf csf.tgz
$ sudo docker diff csf A /var/lib/csf A /var/lib/csf/backup A /var/lib/csf/lock A /usr/sbin/lfd A /usr/sbin/csf A /usr/local/man/man1/csf.1 A /usr/local/csf/lib A /usr/local/csf/bin A /etc/logrotate.d/lfd A /etc/csf A /etc/rc.d/init.d/csf A /etc/rc.d/init.d/lfd A /etc/cron.d/csf-cron A /etc/cron.d/lfd-cron ...