Welcome back! In this post I will cover my experience going over chapter 3 “First Steps” from the book “Using Docker” by Adrian Mouat published by O’REILLY. It is a fact that when you read a technical book you will not be able to learn as much as if you spend the time in front of a computer experimenting and making mistakes.
In this post I will cover some of my experimentation with the concepts presented in the third chapter of the book. If you are reading this post, I strongly recommend reading the third chapter, then experiment with the concepts and finally go over this post. You never know which things you might have missed to understand by only reading.
I am experimenting with Docker on Linux. Sometime ago I spent time with an earlier version of Docker on Windows. I am sure you can use Docker on different cloud platforms (i.e., AWS, Azure and Google).
For starters you need to have Docker installed. Their web site contains helpful information on how to get this done. Last year I installed Docker on one of my Linux machines running CentOS 7. For this post I made sure all was well and started experimenting. If interested, you could check my previous post here.
When I am starting to work with Docker I like to make sure that all is up and running.
# **** check start and stop Docker (1) **** $ docker version Client: Version: 18.09.2 API version: 1.39 Go version: go1.10.6 Git commit: 6247962 Built: Sun Feb 10 04:13:27 2019 OS/Arch: linux/amd64 Experimental: false Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running? $ sudo service docker start Redirecting to /bin/systemctl start docker.service $ docker version Client: Version: 18.09.2 API version: 1.39 Go version: go1.10.6 Git commit: 6247962 Built: Sun Feb 10 04:13:27 2019 OS/Arch: linux/amd64 Experimental: false Server: Docker Engine - Community Engine: Version: 18.09.2 API version: 1.39 (minimum version 1.12) Go version: go1.10.6 Git commit: 6247962 Built: Sun Feb 10 03:47:25 2019 OS/Arch: linux/amd64 Experimental: false $ sudo service docker stop Redirecting to /bin/systemctl stop docker.service
I issue the docker version command. As you can see, if the Docker daemon is not responding chances are that it is not running. After restarting it you should get information about the Docker engine. The last command in the previous screen capture shows how to stop the Docker daemon. You can also restart it if you feel the need.
# **** run a container and display a message (2)**** $ docker run debian echo "Hello John!!!" Hello John!!! $ docker run ubuntu echo "Hello World!!!" Unable to find image 'ubuntu:latest' locally latest: Pulling from library/ubuntu 6cf436f81810: Pull complete 987088a85b96: Pull complete b4624b3efe06: Pull complete d42beb8ded59: Pull complete Digest: sha256:7a47ccc3bbe8a451b500d2b53104868b46d60ee8f5b35a24b41a86077c650210 Status: Downloaded newer image for ubuntu:latest Hello World!!! $ docker run debian echo "Hello John!!!" Hello John!!! $ docker run ubuntu echo "Hello World!!!" Hello World!!!
In this example, we started a Debian image and requested it to run the echo shell command with a specified string.
The second command is quite similar but in that case we requested to use a Linux Ubuntu image which I did not have in my machine. Docker pulled it down from a repository, started a container and passed the command to display a welcome message.
As you can see, when an image is reused, if it is up to date, Docker uses your local copy and starts a microservice passing it the desired command.
# **** docker run -i -t (3) **** $ docker run -i -t debian /bin/bash root@683155bd7506:/# whoami root root@683155bd7506:/# echo "This is a test" This is a test root@683155bd7506:/# echo "How are you?" How are you? root@683155bd7506:/# whoami root root@683155bd7506:/# echo "How are you?" How are you? root@b2d13846a6a4:/# uname -a Linux b2d13846a6a4 3.10.0-957.5.1.el7.x86_64 #1 SMP Fri Feb 1 14:54:57 UTC 2019 x86_64 GNU/Linux root@b2d13846a6a4:/# exit exit $
We can also start a shell in a new microservice. In this case we used the Debian image and asked Docker to keep STDIN open to run an interactive session using a TTY interface. You can get help on Docker commands by entering “Docker help” or “Docker help run” at the command prompt. This is illustrated in the following screen capture:
# **** docker help (4) **** $ docker help run Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...] Run a command in a new container Options: --add-host list Add a custom host-to-IP mapping (host:ip) -a, --attach list Attach to STDIN, STDOUT or STDERR --blkio-weight uint16 Block IO (relative weight), between 10 and 1000, or 0 to disable (default 0) --blkio-weight-device list Block IO weight (relative device weight) (default []) --cap-add list Add Linux capabilities --cap-drop list Drop Linux capabilities --cgroup-parent string Optional parent cgroup for the container --cidfile string Write the container ID to the file --cpu-period int Limit CPU CFS (Completely Fair Scheduler) period --cpu-quota int Limit CPU CFS (Completely Fair Scheduler) quota --cpu-rt-period int Limit CPU real-time period in microseconds --cpu-rt-runtime int Limit CPU real-time runtime in microseconds -c, --cpu-shares int CPU shares (relative weight) --cpus decimal Number of CPUs --cpuset-cpus string CPUs in which to allow execution (0-3, 0,1) --cpuset-mems string MEMs in which to allow execution (0-3, 0,1) -d, --detach Run container in background and print container ID --detach-keys string Override the key sequence for detaching a container --device list Add a host device to the container --device-cgroup-rule list Add a rule to the cgroup allowed devices list --device-read-bps list Limit read rate (bytes per second) from a device (default []) --device-read-iops list Limit read rate (IO per second) from a device (default []) --device-write-bps list Limit write rate (bytes per second) to a device (default []) --device-write-iops list Limit write rate (IO per second) to a device (default []) --disable-content-trust Skip image verification (default true) --dns list Set custom DNS servers --dns-option list Set DNS options --dns-search list Set custom DNS search domains --entrypoint string Overwrite the default ENTRYPOINT of the image -e, --env list Set environment variables --env-file list Read in a file of environment variables --expose list Expose a port or a range of ports --group-add list Add additional groups to join --health-cmd string Command to run to check health --health-interval duration Time between running the check (ms|s|m|h) (default 0s) --health-retries int Consecutive failures needed to report unhealthy --health-start-period duration Start period for the container to initialize before starting health-retries countdown (ms|s|m|h) (default 0s) --health-timeout duration Maximum time to allow one check to run (ms|s|m|h) (default 0s) --help Print usage -h, --hostname string Container host name --init Run an init inside the container that forwards signals and reaps processes -i, --interactive Keep STDIN open even if not attached --ip string IPv4 address (e.g., 172.30.100.104) --ip6 string IPv6 address (e.g., 2001:db8::33) --ipc string IPC mode to use --isolation string Container isolation technology --kernel-memory bytes Kernel memory limit -l, --label list Set meta data on a container --label-file list Read in a line delimited file of labels --link list Add link to another container --link-local-ip list Container IPv4/IPv6 link-local addresses --log-driver string Logging driver for the container --log-opt list Log driver options --mac-address string Container MAC address (e.g., 92:d0:c6:0a:29:33) -m, --memory bytes Memory limit --memory-reservation bytes Memory soft limit --memory-swap bytes Swap limit equal to memory plus swap: '-1' to enable unlimited swap --memory-swappiness int Tune container memory swappiness (0 to 100) (default -1) --mount mount Attach a filesystem mount to the container --name string Assign a name to the container --network string Connect a container to a network (default "default") --network-alias list Add network-scoped alias for the container --no-healthcheck Disable any container-specified HEALTHCHECK --oom-kill-disable Disable OOM Killer --oom-score-adj int Tune host's OOM preferences (-1000 to 1000) --pid string PID namespace to use --pids-limit int Tune container pids limit (set -1 for unlimited) --privileged Give extended privileges to this container -p, --publish list Publish a container's port(s) to the host -P, --publish-all Publish all exposed ports to random ports --read-only Mount the container's root filesystem as read only --restart string Restart policy to apply when a container exits (default "no") --rm Automatically remove the container when it exits --runtime string Runtime to use for this container --security-opt list Security Options --shm-size bytes Size of /dev/shm --sig-proxy Proxy received signals to the process (default true) --stop-signal string Signal to stop a container (default "SIGTERM") --stop-timeout int Timeout (in seconds) to stop a container --storage-opt list Storage driver options for the container --sysctl map Sysctl options (default map[]) --tmpfs list Mount a tmpfs directory -t, --tty Allocate a pseudo-TTY --ulimit ulimit Ulimit options (default []) -u, --user string Username or UID (format: <name|uid>[:<group|gid>]) --userns string User namespace to use --uts string UTS namespace to use -v, --volume list Bind mount a volume --volume-driver string Optional volume driver for the container --volumes-from list Mount volumes from the specified container(s) -w, --workdir string Working directory inside the container
In the next screen capture we run a container. We interact with the bash shell and move the /bin folder to the /basket folder. Let’s see what happens and what can we find about what we did.
# **** create and damage a container and inspect it (5) **** $ docker run -h container -i -t debian /bin/bash root@container:/# uname -a Linux container 3.10.0-957.5.1.el7.x86_64 #1 SMP Fri Feb 1 14:54:57 UTC 2019 x86_64 GNU/Linux root@container:/# mv /bin /basket root@container:/# ls bash: ls: command not found root@container:/# $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES ed6681b6bef7 debian "/bin/bash" 12 minutes ago Up 12 minutes happy_driscoll $ docker inspect happy_driscoll [ { "Id": "ed6681b6bef74239d9c953adda98cb184902bc6b8bee7d6ecbc91a54e4364018", "Created": "2019-02-22T20:18:05.535986117Z", "Path": "/bin/bash", "Args": [], "State": { "Status": "running", "Running": true, "Paused": false, "Restarting": false, "OOMKilled": false, "Dead": false, "Pid": 22645, "ExitCode": 0, "Error": "", "StartedAt": "2019-02-22T20:18:06.313357844Z", "FinishedAt": "0001-01-01T00:00:00Z" }, "Image": "sha256:1b3ec9d977fb413627aca6244b27538013905167db25702a500474616ac2e3c8", "ResolvConfPath": "/var/lib/docker/containers/ed6681b6bef74239d9c953adda98cb184902bc6b8bee7d6ecbc91a54e4364018/resolv.conf", "HostnamePath": "/var/lib/docker/containers/ed6681b6bef74239d9c953adda98cb184902bc6b8bee7d6ecbc91a54e4364018/hostname", "HostsPath": "/var/lib/docker/containers/ed6681b6bef74239d9c953adda98cb184902bc6b8bee7d6ecbc91a54e4364018/hosts", "LogPath": "/var/lib/docker/containers/ed6681b6bef74239d9c953adda98cb184902bc6b8bee7d6ecbc91a54e4364018/ed6681b6bef74239d9c953adda98cb184902bc6b8bee7d6ecbc91a54e4364018-json.log", "Name": "/happy_driscoll", "RestartCount": 0, "Driver": "overlay2", "Platform": "linux", "MountLabel": "", "ProcessLabel": "", "AppArmorProfile": "", "ExecIDs": null, "HostConfig": { "Binds": null, "ContainerIDFile": "", "LogConfig": { "Type": "json-file", "Config": {} }, "NetworkMode": "default", "PortBindings": {}, "RestartPolicy": { "Name": "no", "MaximumRetryCount": 0 }, "AutoRemove": false, "VolumeDriver": "", "VolumesFrom": null, "CapAdd": null, "CapDrop": null, "Dns": [], "DnsOptions": [], "DnsSearch": [], "ExtraHosts": null, "GroupAdd": null, "IpcMode": "shareable", "Cgroup": "", "Links": null, "OomScoreAdj": 0, "PidMode": "", "Privileged": false, "PublishAllPorts": false, "ReadonlyRootfs": false, "SecurityOpt": null, "UTSMode": "", "UsernsMode": "", "ShmSize": 67108864, "Runtime": "runc", "ConsoleSize": [ 0, 0 ], "Isolation": "", "CpuShares": 0, "Memory": 0, "NanoCpus": 0, "CgroupParent": "", "BlkioWeight": 0, "BlkioWeightDevice": [], "BlkioDeviceReadBps": null, "BlkioDeviceWriteBps": null, "BlkioDeviceReadIOps": null, "BlkioDeviceWriteIOps": null, "CpuPeriod": 0, "CpuQuota": 0, "CpuRealtimePeriod": 0, "CpuRealtimeRuntime": 0, "CpusetCpus": "", "CpusetMems": "", "Devices": [], "DeviceCgroupRules": null, "DiskQuota": 0, "KernelMemory": 0, "MemoryReservation": 0, "MemorySwap": 0, "MemorySwappiness": null, "OomKillDisable": false, "PidsLimit": 0, "Ulimits": null, "CpuCount": 0, "CpuPercent": 0, "IOMaximumIOps": 0, "IOMaximumBandwidth": 0, "MaskedPaths": [ "/proc/asound", "/proc/acpi", "/proc/kcore", "/proc/keys", "/proc/latency_stats", "/proc/timer_list", "/proc/timer_stats", "/proc/sched_debug", "/proc/scsi", "/sys/firmware" ], "ReadonlyPaths": [ "/proc/bus", "/proc/fs", "/proc/irq", "/proc/sys", "/proc/sysrq-trigger" ] }, "GraphDriver": { "Data": { "LowerDir": "/var/lib/docker/overlay2/4d257caf5eb1e56c3e243f84b84071274d070cdc875b55e3e5392404b8cec702-init/diff:/var/lib/docker/overlay2/42c4b2ba5b2f938f3663f21d1d91c7882056d90502147ffafdd005a1d596bf5d/diff", "MergedDir": "/var/lib/docker/overlay2/4d257caf5eb1e56c3e243f84b84071274d070cdc875b55e3e5392404b8cec702/merged", "UpperDir": "/var/lib/docker/overlay2/4d257caf5eb1e56c3e243f84b84071274d070cdc875b55e3e5392404b8cec702/diff", "WorkDir": "/var/lib/docker/overlay2/4d257caf5eb1e56c3e243f84b84071274d070cdc875b55e3e5392404b8cec702/work" }, "Name": "overlay2" }, "Mounts": [], "Config": { "Hostname": "container", "Domainname": "", "User": "", "AttachStdin": true, "AttachStdout": true, "AttachStderr": true, "Tty": true, "OpenStdin": true, "StdinOnce": true, "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], "Cmd": [ "/bin/bash" ], "Image": "debian", "Volumes": null, "WorkingDir": "", "Entrypoint": null, "OnBuild": null, "Labels": {} }, "NetworkSettings": { "Bridge": "", "SandboxID": "f9c32d774e2b20878fec78d24b0cfb0b7fad4f0530b8f9d1ea2a712fde22b9ff", "HairpinMode": false, "LinkLocalIPv6Address": "", "LinkLocalIPv6PrefixLen": 0, "Ports": {}, "SandboxKey": "/var/run/docker/netns/f9c32d774e2b", "SecondaryIPAddresses": null, "SecondaryIPv6Addresses": null, "EndpointID": "a2a4afefd1cfb6dc751930bb793d3fc230ade6d921d4a7f547fe3d786ce0a80d", "Gateway": "172.17.0.1", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "MacAddress": "02:42:ac:11:00:02", "Networks": { "bridge": { "IPAMConfig": null, "Links": null, "Aliases": null, "NetworkID": "1bd33f685f4a0b5dc59abb4ac9c4582158c634f0d8dcacc4f297d123d457c249", "EndpointID": "a2a4afefd1cfb6dc751930bb793d3fc230ade6d921d4a7f547fe3d786ce0a80d", "Gateway": "172.17.0.1", "IPAddress": "172.17.0.2", "IPPrefixLen": 16, "IPv6Gateway": "", "GlobalIPv6Address": "", "GlobalIPv6PrefixLen": 0, "MacAddress": "02:42:ac:11:00:02", "DriverOpts": null } } } } ] $ docker inspect happy_driscoll | grep "IPAddress" "SecondaryIPAddresses": null, "IPAddress": "172.17.0.2", "IPAddress": "172.17.0.2", $ ping 172.17.0.2 PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data. 64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.088 ms 64 bytes from 172.17.0.2: icmp_seq=2 ttl=64 time=0.059 ms 64 bytes from 172.17.0.2: icmp_seq=3 ttl=64 time=0.043 ms 64 bytes from 172.17.0.2: icmp_seq=4 ttl=64 time=0.036 ms 64 bytes from 172.17.0.2: icmp_seq=5 ttl=64 time=0.054 ms 64 bytes from 172.17.0.2: icmp_seq=6 ttl=64 time=0.059 ms 64 bytes from 172.17.0.2: icmp_seq=7 ttl=64 time=0.036 ms 64 bytes from 172.17.0.2: icmp_seq=8 ttl=64 time=0.050 ms 64 bytes from 172.17.0.2: icmp_seq=9 ttl=64 time=0.045 ms 64 bytes from 172.17.0.2: icmp_seq=10 ttl=64 time=0.040 ms 64 bytes from 172.17.0.2: icmp_seq=11 ttl=64 time=0.047 ms ^C --- 172.17.0.2 ping statistics --- 11 packets transmitted, 11 received, 0% packet loss, time 9999ms rtt min/avg/max/mdev = 0.036/0.050/0.088/0.016 ms $ docker inspect happy_driscoll | grep "Hostname" "HostnamePath": "/var/lib/docker/containers/ed6681b6bef74239d9c953adda98cb184902bc6b8bee7d6ecbc91a54e4364018/hostname", "Hostname": "container", $ docker diff happy_driscoll A /basket A /basket/zfgrep A /basket/gunzip A /basket/ping6 A /basket/zcmp A /basket/grep A /basket/su A /basket/dd A /basket/dnsdomainname A /basket/echo A /basket/tar A /basket/wdctl A /basket/chmod A /basket/findmnt A /basket/more A /basket/egrep A /basket/run-parts A /basket/zdiff A /basket/sleep A /basket/zless A /basket/chown A /basket/cp A /basket/gzexe A /basket/touch A /basket/zmore A /basket/domainname A /basket/mount A /basket/tailf A /basket/rbash A /basket/vdir A /basket/znew A /basket/stty A /basket/zforce A /basket/df A /basket/ip A /basket/sed A /basket/ping A /basket/pwd A /basket/true A /basket/ypdomainname A /basket/mv A /basket/nisdomainname A /basket/pidof A /basket/readlink A /basket/zgrep A /basket/cat A /basket/dir A /basket/false A /basket/sh.distrib A /basket/ss A /basket/tempfile A /basket/uncompress A /basket/zcat A /basket/dash A /basket/dmesg A /basket/mktemp A /basket/mountpoint A /basket/rmdir A /basket/which A /basket/chgrp A /basket/gzip A /basket/hostname A /basket/uname A /basket/zegrep A /basket/lsblk A /basket/rm A /basket/sync A /basket/ls A /basket/mkdir A /basket/sh A /basket/umount A /basket/fgrep A /basket/ln A /basket/login A /basket/bash A /basket/date A /basket/mknod D /bin
We definitely rendered unusable the microservice. After we exit the shell we check if the microservice is running. It seems it is still around. We can now inspect it and get a large amount of information as we can see in the output of the docker inspect command. As we get more familiar we can specify what we need by piping the “inspect” command to grep. In this case we are interested in the IP.
Once we get the IP, we are able to ping it from our console. We can also get the host name used by our container.
If we use the “docker diff” command we can see that some folders were appended “A” to the file system and one was deleted “D”. These are the results of the mv command we issued.
# **** exit the shell in the container (6) **** root@container:/# exit exit $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES $ docker rm happy_driscoll happy_driscoll
In the last screen capture we exit from the shell of the container. We check that we do not have containers running using the “docker ps” command and we remove the happy_driscoll container. The unique name comes from Docker. If you do not assign a name to a container, Docker does it for you.
# **** remove exited containers (7)**** $ docker rm -v $(docker ps -aq -f status=exited) c3dbb5f7a9c3 b2d13846a6a4 683155bd7506 0ff06b0179f0 b048c489380e e30e366505dc 004c767ea207 2d11d4d477f9 ed7b0d2e2005 06cbab8bc22a 359981fceeac 44cf60a90c60 7e54f3a173a8 ae502e0268d9 5824ee5dbae0 b157a29fe4c1 f9568b4820ce 67de28eba86a 1d6951788ebf 367c20bef351 fef40a90b975 488b4ff9532f ef1a4e5ba280 403044466fef 02453c26151c 882a3bcaf9a5 385bdf2674da b9ba5e3ad4dd 33158afa30fa $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES $
When you work with containers, you may end up with dozens which acted as a step in a long journey. In addition we just checked if we have containers running. It seems that all is well and clean.
Next we are going to create a microservice cowsay that will display some text defined by the user or a quote. You can download and install the two parts in your computer or you can just build a microservice and use it as needed.
# **** cowsay (8) **** $ docker run -it --name cowsay --hostname cowsay debian bash root@cowsay:/# apt-get update Get:1 http://security.debian.org stretch/updates InRelease [94.3 kB] Ign:2 http://deb.debian.org/debian stretch InRelease Get:3 http://security.debian.org stretch/updates/main amd64 Packages [592 kB] Get:4 http://deb.debian.org/debian stretch-updates InRelease [91.0 kB] Get:5 http://deb.debian.org/debian stretch Release [118 kB] Get:6 http://deb.debian.org/debian stretch-updates/main amd64 Packages [12.3 kB] Get:7 http://deb.debian.org/debian stretch Release.gpg [2434 B] Get:8 http://deb.debian.org/debian stretch/main amd64 Packages [9478 kB] Fetched 10.4 MB in 2s (4062 kB/s) Reading package lists... Done root@cowsay:/#
We created a new microservice using the Debian image which we did not have in our local machine. We are running are interactive session and using the bash shell.
# **** apt-get (9) **** root@cowsay:/# apt-get apt 1.4.8 (amd64) Usage: apt-get [options] command apt-get [options] install|remove pkg1 [pkg2 ...] apt-get [options] source pkg1 [pkg2 ...] apt-get is a command line interface for retrieval of packages and information about them from authenticated sources and for installation, upgrade and removal of packages together with their dependencies. Most used commands: update - Retrieve new lists of packages upgrade - Perform an upgrade install - Install new packages (pkg is libc6 not libc6.deb) remove - Remove packages purge - Remove packages and config files autoremove - Remove automatically all unused packages dist-upgrade - Distribution upgrade, see apt-get(8) dselect-upgrade - Follow dselect selections build-dep - Configure build-dependencies for source packages clean - Erase downloaded archive files autoclean - Erase old downloaded archive files check - Verify that there are no broken dependencies source - Download source archives download - Download the binary package into the current directory changelog - Download and display the changelog for the given package See apt-get(8) for more information about the available commands. Configuration options and syntax is detailed in apt.conf(5). Information about how to configure sources can be found in sources.list(5). Package and version choices can be expressed via apt_preferences(5). Security details are available in apt-secure(8). This APT has Super Cow Powers. root@cowsay:/#
The apt-get is a package handling utility found in most Linux distributions. It happens that it is available in the Debian distribution. It is quite simple to use and we will in the next screen capture.
# **** install cowsay and fortune (10) **** root@cowsay:~# apt-get install -y cowsay fortune Reading package lists... Done Building dependency tree Reading state information... Done Note, selecting 'fortune-mod' instead of 'fortune' The following additional packages will be installed: cowsay-off fortunes-min libgdbm3 libperl5.24 librecode0 libtext-charwidth-perl perl perl-base perl-modules-5.24 rename Suggested packages: filters fortunes x11-utils bsdmainutils perl-doc libterm-readline-gnu-perl | libterm-readline-perl-perl make The following NEW packages will be installed: cowsay cowsay-off fortune-mod fortunes-min libgdbm3 libperl5.24 librecode0 libtext-charwidth-perl perl perl-modules-5.24 rename The following packages will be upgraded: perl-base 1 upgraded, 11 newly installed, 0 to remove and 27 not upgraded. Need to get 8522 kB of archives. After this operation, 42.6 MB of additional disk space will be used. Get:1 http://deb.debian.org/debian stretch/main amd64 perl-base amd64 5.24.1-3+deb9u5 [1345 kB] Get:2 http://deb.debian.org/debian stretch/main amd64 perl-modules-5.24 all 5.24.1-3+deb9u5 [2722 kB] Get:3 http://deb.debian.org/debian stretch/main amd64 libgdbm3 amd64 1.8.3-14 [30.0 kB] Get:4 http://deb.debian.org/debian stretch/main amd64 libperl5.24 amd64 5.24.1-3+deb9u5 [3501 kB] Get:5 http://deb.debian.org/debian stretch/main amd64 perl amd64 5.24.1-3+deb9u5 [219 kB] Get:6 http://deb.debian.org/debian stretch/main amd64 libtext-charwidth-perl amd64 0.04-7+b5 [9870 B] Get:7 http://deb.debian.org/debian stretch/main amd64 cowsay all 3.03+dfsg2-3 [20.1 kB] Get:8 http://deb.debian.org/debian stretch/main amd64 cowsay-off all 3.03+dfsg2-3 [7816 B] Get:9 http://deb.debian.org/debian stretch/main amd64 librecode0 amd64 3.6-23 [532 kB] Get:10 http://deb.debian.org/debian stretch/main amd64 fortune-mod amd64 1:1.99.1-7+b1 [49.5 kB] Get:11 http://deb.debian.org/debian stretch/main amd64 fortunes-min all 1:1.99.1-7 [74.3 kB] Get:12 http://deb.debian.org/debian stretch/main amd64 rename all 0.20-4 [12.5 kB] Fetched 8522 kB in 1s (6771 kB/s) debconf: delaying package configuration, since apt-utils is not installed (Reading database ... 6487 files and directories currently installed.) Preparing to unpack .../perl-base_5.24.1-3+deb9u5_amd64.deb ... Unpacking perl-base (5.24.1-3+deb9u5) over (5.24.1-3+deb9u2) ... Setting up perl-base (5.24.1-3+deb9u5) ... Selecting previously unselected package perl-modules-5.24. (Reading database ... 6487 files and directories currently installed.) Preparing to unpack .../00-perl-modules-5.24_5.24.1-3+deb9u5_all.deb ... Unpacking perl-modules-5.24 (5.24.1-3+deb9u5) ... Selecting previously unselected package libgdbm3:amd64. Preparing to unpack .../01-libgdbm3_1.8.3-14_amd64.deb ... Unpacking libgdbm3:amd64 (1.8.3-14) ... Selecting previously unselected package libperl5.24:amd64. Preparing to unpack .../02-libperl5.24_5.24.1-3+deb9u5_amd64.deb ... Unpacking libperl5.24:amd64 (5.24.1-3+deb9u5) ... Selecting previously unselected package perl. Preparing to unpack .../03-perl_5.24.1-3+deb9u5_amd64.deb ... Unpacking perl (5.24.1-3+deb9u5) ... Selecting previously unselected package libtext-charwidth-perl. Preparing to unpack .../04-libtext-charwidth-perl_0.04-7+b5_amd64.deb ... Unpacking libtext-charwidth-perl (0.04-7+b5) ... Selecting previously unselected package cowsay. Preparing to unpack .../05-cowsay_3.03+dfsg2-3_all.deb ... Unpacking cowsay (3.03+dfsg2-3) ... Selecting previously unselected package cowsay-off. Preparing to unpack .../06-cowsay-off_3.03+dfsg2-3_all.deb ... Unpacking cowsay-off (3.03+dfsg2-3) ... Selecting previously unselected package librecode0:amd64. Preparing to unpack .../07-librecode0_3.6-23_amd64.deb ... Unpacking librecode0:amd64 (3.6-23) ... Selecting previously unselected package fortune-mod. Preparing to unpack .../08-fortune-mod_1%3a1.99.1-7+b1_amd64.deb ... Unpacking fortune-mod (1:1.99.1-7+b1) ... Selecting previously unselected package fortunes-min. Preparing to unpack .../09-fortunes-min_1%3a1.99.1-7_all.deb ... Unpacking fortunes-min (1:1.99.1-7) ... Selecting previously unselected package rename. Preparing to unpack .../10-rename_0.20-4_all.deb ... Unpacking rename (0.20-4) ... Setting up perl-modules-5.24 (5.24.1-3+deb9u5) ... Setting up libgdbm3:amd64 (1.8.3-14) ... Setting up libperl5.24:amd64 (5.24.1-3+deb9u5) ... Setting up fortunes-min (1:1.99.1-7) ... Setting up perl (5.24.1-3+deb9u5) ... update-alternatives: using /usr/bin/prename to provide /usr/bin/rename (rename) in auto mode Processing triggers for libc-bin (2.24-11+deb9u1) ... Setting up librecode0:amd64 (3.6-23) ... Setting up libtext-charwidth-perl (0.04-7+b5) ... Setting up fortune-mod (1:1.99.1-7+b1) ... Setting up cowsay (3.03+dfsg2-3) ... Setting up cowsay-off (3.03+dfsg2-3) ... Setting up rename (0.20-4) ... update-alternatives: using /usr/bin/file-rename to provide /usr/bin/rename (rename) in auto mode Processing triggers for libc-bin (2.24-11+deb9u1) ... root@cowsay:~# ls -l /usr/games total 36 -rwxr-xr-x. 1 root root 4664 Jan 16 2017 cowsay lrwxrwxrwx. 1 root root 6 Jan 16 2017 cowthink -> cowsay -rwxr-xr-x. 1 root root 27320 Aug 15 2013 fortune root@cowsay:~# /usr/games/fortune You attempt things that you do not even plan because of your extreme stupidity. root@cowsay:~# /usr/games/fortune You're ugly and your mother dresses you funny. root@cowsay:~# /usr/games/fortune You are capable of planning your future.
We need to install the cowsay package which displays a cow with a caption. The text for the caption can be piped in from the console (e.g., echo “Hello John”) or from fortune into cowsay. It is interesting to see the end result.
We can see that cowsay and fortune were installed in the microservice in the /usr/games folder. If you have not used fortune it displays quotes. The program was available on UNIX. Most developers at work including myself, used to display a quote when you would log into your machine.
# **** echo and fortune | cowsay (11) **** root@cowsay:~# echo "Hello John" | /usr/games/cowsay ____________ < Hello John > ------------ \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || root@cowsay:~# /usr/games/fortune | /usr/games/cowsay ________________________________________ < Your ignorance cramps my conversation. > ---------------------------------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || root@cowsay:~#
We echoed “Hello John” and piped it to cowsay. A cow is displayed with a caption holding the text you entered. In the second invocation we just piped a fortune into cowsay. Pretty nifty I would say.
# **** save the cowsay image (12) **** root@cowsay:~# exit exit $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 3c320cc69f32 debian "bash" 25 minutes ago Exited (1) 15 seconds ago cowsay $ pwd /home/johncanessa/Docker $ docker commit cowsay test/cowsayimage sha256:e5a22e4037288055708bdd64be834c2ef6e4ebe972964fa6109f10d222d5429b
We exit the microservice. We verify that the microservice has exited using the “docker ps” command. I checked our current directory and then used “docker commit” to save the cowsay image into our local repository (not current folder).
# **** run the saved image (13) **** $ docker run test/cowsayimage /usr/games/cowsay "Hello John !!!" ________________ < Hello John !!! > ---------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || || # **** list or images **** $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE test/cowsayimage latest e5a22e403728 4 minutes ago 164MB ubuntu latest 47b19964fb50 2 weeks ago 88.1MB debian latest 1b3ec9d977fb 12 months ago 100MB centos latest ff426288ea90 13 months ago 207MB
We just run the container we created. It seems to work. In addition we use the “docker images” command to list the images we have locally. The test/cowsayimage is there.
# **** run cowsay by image ID (14) **** $ docker run e5a22e403728 /usr/games/cowsay "Hello" _______ < Hello > ------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||
We ran the image in a microservice but we called it by ID instead of by name.
# **** build image using Dockerfile (15) **** $ mkdir cowsay $ cd cowsay/ $ touch Dockerfile $ ls -al total 0 drwxr-xr-x. 2 johncanessa johncanessa 24 Feb 22 15:37 . drwxr-xr-x. 3 johncanessa johncanessa 102 Feb 22 15:37 .. -rw-r--r--. 1 johncanessa johncanessa 0 Feb 22 15:37 Dockerfile
In this screen capture we make a directory and move to it. We then create an empty file named Dockerfile.
# **** edit Docker file as follows (16) **** $ cat Dockerfile FROM debian:wheezy RUN apt-get update && apt-get install -y cowsay fortune
We edited the Dockerfile and added two lines. Each line represents a command. In the first line we tell Docker to use a fresh copy of the Debian image labeled wheezy. In the second we want to install cowsay and fortune.
# **** build the image (17) **** $ pwd /home/johncanessa/Docker/cowsay $ ls Dockerfile $ docker build -t test/cowsay-dockerfile . Sending build context to Docker daemon 2.048kB Step 1/2 : FROM debian:wheezy ---> 8c971baff57b Step 2/2 : RUN apt-get update && apt-get install -y cowsay fortune ---> Running in fb3769c00c90 Get:1 http://deb.debian.org wheezy Release.gpg [2373 B] Get:2 http://deb.debian.org wheezy-updates Release.gpg [1601 B] Get:3 http://deb.debian.org wheezy Release [191 kB] Get:4 http://deb.debian.org wheezy-updates Release [155 kB] Get:5 http://deb.debian.org wheezy/main amd64 Packages [7634 kB] Get:6 http://deb.debian.org wheezy-updates/main amd64 Packages [7481 B] Get:7 http://security.debian.org wheezy/updates Release.gpg [1601 B] Get:8 http://security.debian.org wheezy/updates Release [52.3 kB] Get:9 http://security.debian.org wheezy/updates/main amd64 Packages [743 kB] Fetched 8788 kB in 2min 6s (69.5 kB/s) Reading package lists... Reading package lists... Building dependency tree... Reading state information... The following extra packages will be installed: fortunes-min ifupdown libclass-isa-perl libgdbm3 librecode0 libswitch-perl netbase perl perl-modules Suggested packages: filters fortunes x11-utils bsdmainutils isc-dhcp-client dhcp-client ppp rdnssd net-tools perl-doc libterm-readline-gnu-perl libterm-readline-perl-perl make libpod-plainer-perl The following NEW packages will be installed: cowsay fortune-mod fortunes-min ifupdown libclass-isa-perl libgdbm3 librecode0 libswitch-perl netbase perl perl-modules 0 upgraded, 11 newly installed, 0 to remove and 0 not upgraded. Need to get 8965 kB of archives. After this operation, 34.7 MB of additional disk space will be used. Get:1 http://deb.debian.org/debian/ wheezy/main ifupdown amd64 0.7.8 [64.9 kB] Get:2 http://deb.debian.org/debian/ wheezy/main libgdbm3 amd64 1.8.3-11 [46.9 kB] Get:3 http://deb.debian.org/debian/ wheezy/main librecode0 amd64 3.6-20 [779 kB] Get:4 http://deb.debian.org/debian/ wheezy/main netbase all 5.0 [20.1 kB] Get:5 http://deb.debian.org/debian/ wheezy/main libclass-isa-perl all 0.36-3 [12.3 kB] Get:6 http://deb.debian.org/debian/ wheezy/main libswitch-perl all 2.16-2 [21.0 kB] Get:7 http://deb.debian.org/debian/ wheezy/main cowsay all 3.03+dfsg1-4 [21.9 kB] Get:8 http://deb.debian.org/debian/ wheezy/main fortune-mod amd64 1:1.99.1-4 [51.3 kB] Get:9 http://deb.debian.org/debian/ wheezy/main fortunes-min all 1:1.99.1-4 [73.0 kB] Get:10 http://security.debian.org/debian-security/ wheezy/updates/main perl-modules all 5.14.2-21+deb7u6 [3441 kB] Get:11 http://security.debian.org/debian-security/ wheezy/updates/main perl amd64 5.14.2-21+deb7u6 [4434 kB] debconf: delaying package configuration, since apt-utils is not installed Fetched 8965 kB in 2min 0s (74.2 kB/s) Selecting previously unselected package ifupdown. (Reading database ... 6755 files and directories currently installed.) Unpacking ifupdown (from .../ifupdown_0.7.8_amd64.deb) ... Selecting previously unselected package libgdbm3:amd64. Unpacking libgdbm3:amd64 (from .../libgdbm3_1.8.3-11_amd64.deb) ... Selecting previously unselected package librecode0:amd64. Unpacking librecode0:amd64 (from .../librecode0_3.6-20_amd64.deb) ... Selecting previously unselected package netbase. Unpacking netbase (from .../archives/netbase_5.0_all.deb) ... Selecting previously unselected package libclass-isa-perl. Unpacking libclass-isa-perl (from .../libclass-isa-perl_0.36-3_all.deb) ... Selecting previously unselected package perl-modules. Unpacking perl-modules (from .../perl-modules_5.14.2-21+deb7u6_all.deb) ... Selecting previously unselected package perl. Unpacking perl (from .../perl_5.14.2-21+deb7u6_amd64.deb) ... Selecting previously unselected package libswitch-perl. Unpacking libswitch-perl (from .../libswitch-perl_2.16-2_all.deb) ... Selecting previously unselected package cowsay. Unpacking cowsay (from .../cowsay_3.03+dfsg1-4_all.deb) ... Selecting previously unselected package fortune-mod. Unpacking fortune-mod (from .../fortune-mod_1%3a1.99.1-4_amd64.deb) ... Selecting previously unselected package fortunes-min. Unpacking fortunes-min (from .../fortunes-min_1%3a1.99.1-4_all.deb) ... Setting up ifupdown (0.7.8) ... Creating /etc/network/interfaces. Setting up libgdbm3:amd64 (1.8.3-11) ... Setting up librecode0:amd64 (3.6-20) ... Setting up netbase (5.0) ... Setting up libclass-isa-perl (0.36-3) ... Setting up fortune-mod (1:1.99.1-4) ... Setting up fortunes-min (1:1.99.1-4) ... Setting up libswitch-perl (2.16-2) ... Setting up perl-modules (5.14.2-21+deb7u6) ... Setting up perl (5.14.2-21+deb7u6) ... update-alternatives: using /usr/bin/prename to provide /usr/bin/rename (rename) in auto mode Setting up cowsay (3.03+dfsg1-4) ... Removing intermediate container fb3769c00c90 ---> 2ea885a81c30 Successfully built 2ea885a81c30 Successfully tagged test/cowsay-dockerfile:latest
Now we are ready to run “docker build” to create an image as specified by the Dockerfile we just edited.
# **** list images (18) **** $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE test/cowsay-dockerfile latest 2ea885a81c30 About a minute ago 131MB test/cowsayimage latest e5a22e403728 2 days ago 164MB ubuntu latest 47b19964fb50 2 weeks ago 88.1MB debian wheezy 8c971baff57b 2 weeks ago 88.3MB debian latest 1b3ec9d977fb 12 months ago 100MB centos latest ff426288ea90 13 months ago 207MB
We can see by using “docker images” that we have created in our local repository the image test/cowsay-dockerfile.
# **** running image test/cowsay-dockerfile (19) **** $ docker run test/cowsay-dockerfile /usr/games/cowsay "Hello John!!!" _______________ < Hello John!!! > --------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||
We can test the new image and cowsay displays our message.
# **** determine which Union File Systems is used by Docker (20) **** $ docker info | grep "Storage Driver" Storage Driver: overlay2
Docker uses a union file system to build images. Different file systems have different features. In our case we seem to be using Overlay2. Please do not change the union file system unless you have experience with the different features available.
# **** add ENTRYPOINT to the Dockerfile (21) **** $ cat Dockerfile FROM debian:wheezy RUN apt-get update && apt-get install -y cowsay fortune ENTRYPOINT ["/usr/games/cowsay"]
In the previous command we specified which program should be executed. We can add such information into Dockerfile.
# **** build the image (22) **** $ docker build -t test/cowsay-dockerfile . Sending build context to Docker daemon 2.048kB Step 1/3 : FROM debian:wheezy ---> 8c971baff57b Step 2/3 : RUN apt-get update && apt-get install -y cowsay fortune ---> Using cache ---> 8cd4c4c8cb47 Step 3/3 : ENTRYPOINT ["/usr/games/cowsay"] ---> Running in 5ebc18f7e3e4 Removing intermediate container 5ebc18f7e3e4 ---> 4504a08e5228 Successfully built 4504a08e5228 Successfully tagged test/cowsay-dockerfile:latest $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE test/cowsay-dockerfile latest 4504a08e5228 18 seconds ago 131MB test/cowsayimage latest e5a22e403728 2 days ago 164MB ubuntu latest 47b19964fb50 2 weeks ago 88.1MB debian wheezy 8c971baff57b 2 weeks ago 88.3MB debian latest 1b3ec9d977fb 12 months ago 100MB centos latest ff426288ea90 13 months ago 207MB
We rebuild the image. The image ID has changed.
# **** run the image (23) **** $ docker run test/cowsay-dockerfile "Hi John, again !!!!" _____________________ < Hi John, again !!!! > --------------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||
We can now run the updated image by just passing the string we wish to display.
# **** entrypoint.sh (24) **** $ cat entrypoint.sh #!/bin/bash if [ $# -eq 0]; then /usr/games/fortune /user/games/cowsay else /usr/games/cowsay "$@" fi
The issue with our current solution is that if we do not pass a string, cowsay will display a blank caption. We can solve this by first creating the entrypoint.sh file.
# **** change mode to be able to execute it (25) **** $ chmod +x entrypoint.sh $ ls -l entrypoint.sh -rwxr-xr-x. 1 johncanessa johncanessa 104 Feb 25 13:39 entrypoint.sh
We change the mode to be able to execute it.
# **** edit Dockerfile (26) **** $ cat Dockerfile FROM debian:wheezy RUN apt-get update && apt-get install -y cowsay fortune COPY entrypoint.sh / #COPY entrypoint.ksh / ENTRYPOINT ["/entrypoint.sh"] #ENTRYPOINT ["/entrypoint.ksh"]
We update the Dockerfile. I left a couple lines commented out. The reason was to test what if I write a Korn shell script but the Debian image does not contain the Korn shell. You can comment and edit the appropriate lines and see the results. They appear to be rather cryptic.
# **** buid and execute the image (27) **** $ docker run test/cowsay-dockerfile standard_init_linux.go:207: exec user process caused "no such file or directory"
The following capture illustrates that the Debian image does not include the Korn shell.
# **** no ksh in debian image (28) **** # /etc/shells: valid login shells /bin/sh /bin/dash /bin/bash /bin/rbash root@a0ebfcbcae81:/#
Now that all is working (make sure you are not using the Korn shell) let’s login into Docker Hub.
# **** log into Docker Hub (29) **** $ docker login Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one. Username: johncanessa Password: WARNING! Your password will be stored unencrypted in /home/johncanessa/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded
You need to register for an account for free. This is true if your repository is public. I believe there is a charge for private ones.
# **** build the image for the repository (30) **** $ docker build -t johncanessa/cowsay . Sending build context to Docker daemon 5.12kB Step 1/5 : FROM debian:wheezy ---> 8c971baff57b Step 2/5 : MAINTAINER John Canessa <john.canessa@gmail.com> ---> Using cache ---> 531b2b19d881 Step 3/5 : RUN apt-get update && apt-get install -y cowsay fortune ---> Using cache ---> 0273e5ec1af2 Step 4/5 : COPY entrypoint.sh / ---> Using cache ---> bbde42c4599c Step 5/5 : ENTRYPOINT ["/entrypoint.sh"] ---> Using cache ---> 30d74744acb1 Successfully built 30d74744acb1 Successfully tagged johncanessa/cowsay:latest
We build an image for the repository at Docker Hub.
# **** push the image to the repository (31) **** $ docker push johncanessa/cowsay The push refers to repository [docker.io/johncanessa/cowsay] c360ce0549f2: Pushed 13025371f5d4: Pushed 0e9f3c1de5b3: Mounted from library/debian latest: digest: sha256:98cdcc6365e9e61030bcaf035fa055d59007f3fd818861641a17dea0bffb1553 size: 948
Now that the image has been created we can push it.
# **** make a folder to pull the image (32) **** $ mkdir temp $ cd temp $ pwd /home/johncanessa/temp $ docker pull johncanessa/cowsay Using default tag: latest latest: Pulling from johncanessa/cowsay Digest: sha256:98cdcc6365e9e61030bcaf035fa055d59007f3fd818861641a17dea0bffb1553 Status: Image is up to date for johncanessa/cowsay:latest $ ls -al total 4 drwxr-xr-x. 2 johncanessa johncanessa 6 Feb 25 16:10 . drwx------. 31 johncanessa johncanessa 4096 Feb 25 16:10 ..
We create a local folder to receive the image that we will pull from Docker Hub. We then pull the image using “docker pull”. As we can see the image was not returned to a folder. As we will see in a few more screen captures, the image is placed in our local repository.
# **** remove all images (33) **** $ docker rmi $(docker images -aq) Untagged: johncanessa/cowsay:latest Untagged: johncanessa/cowsay@sha256:98cdcc6365e9e61030bcaf035fa055d59007f3fd818861641a17dea0bffb1553 Deleted: sha256:30d74744acb1d957c9bb85ee7f6eaefcfff2a06ffec085e996a4be7fcb077426 Deleted: sha256:bbde42c4599cdcdb78c7d0043a139a1a6cdb77eaba8db61bd1627b1c54ec032c Deleted: sha256:1d61e0855fafc29ae5c82f73dd3438914b3ab6a4d1b090ca84ec523df4a38ed9 Deleted: sha256:0273e5ec1af24eb4296454a47664da22cc8fdd0994ee1dce39329894a812d873 Deleted: sha256:b0e7648693826c9a5c145509dae3cd30851c25b02f1a0f95bf08456b013871c5 Deleted: sha256:531b2b19d8819bdad653d1a2ccfffc3fdbc97dc90596623b352aaaa1a4ec0161 Untagged: test/cowsay-dockerfile:latest Deleted: sha256:46b203b2adb31ad517c532d0637cbe6311ff21b6945f4955a2d4c4b841753184 Deleted: sha256:1e1762b7d4276ded8e21a9bd3cea1ab681dbbee0f2957dea8cf16eeefe44feda Deleted: sha256:ecebdf102966db54550d4319ad1fd48c1a6e6fed0f50d7e1b0ed5816326fa910 Deleted: sha256:a2881c3b00b34193dfa00f7af64bf7009326fa07172078628f1cf9a629d22f78 Deleted: sha256:e6bc48513b4a2c6aaa7e744538e01234569c59110082e5787f93b88117fa6cff Deleted: sha256:1df45fbba7b4664acc84d6b2a150a9e5c9b7615752e2c2397f922cfe3a09cc59 Deleted: sha256:ced0b68c8a547e5eaaaa5ca1115d40ce149b1e7fa659511dbbc789c6b24053fe Deleted: sha256:351a2d353e3158d7c524181d70be63bfb4fb16edde68bc72fb8d1fcc80607304 Deleted: sha256:91125e99f81e5efd6b0aef2ebff4ad9da577c0bc677b23720c64c75d4d140ddf Deleted: sha256:e069aeea43ebee4fa7dbc3d2fdac93c73280cdb1b72880beaa3e0f348a1ad105 Deleted: sha256:0d39b6306a1b1468f57d01e40425c68e3ed956da26ccf3cb2505fe0822391420 Deleted: sha256:38b289fe568c6f15c7f59f69f731f3db24de75808525b511af15fada6e6272a7 Deleted: sha256:b90bfb8219e4408fc9a52b8bdf1e25f7068d975b99a8efa83255b7817ba89a0d Deleted: sha256:cf6d00692eb772c7692abb3eab9431c48457afe9896e1e5694c106e09b24dc05 Deleted: sha256:83992f1037a6dfef2526d266c9e6a0e457e077c674bc6d5927960a1002b8f977 Deleted: sha256:1b6f3ceb73bfa9a71962706ae7e19eac87a6c7c289085895e20ca92e55615807 Deleted: sha256:d9fbbf8da9a96a4113890e7cf38c36df618db3edcce922c130507c6feadb57ad Deleted: sha256:ec8a4ff13d1e73f2605a0ff0791c4fd33f7ac4f2a719348d58ea0e0c8dd6ebd3 Deleted: sha256:18e260d9c6687c3a8b1936c5015e84360600d1705ca6b5eefad9dd54804f0472 Deleted: sha256:8b0ddef44e8c400a33bb03393a8257010df7513fe8b65add5fb6f5ec819a8e7a Deleted: sha256:f58efd7b7bf2b0f7ba37b96f383138370b323807b6c777319d06973bcfd42698 Deleted: sha256:8dadfd7bfc60c96adf26b307370e6a91256cd35cf210efb08355577016577870 Deleted: sha256:df2c7d3bbaa2443c2769ffebe12bc5b56020e096009ee88259f21c6d4d5a1614 Deleted: sha256:e57f146ec12b4450775d8699f52ad30549a5926c4c53b3fc4a795aec5d748a11 Deleted: sha256:cce26fa707586d937047fb3cf98a38103fc05f85af4543c24c78527c22687421 Deleted: sha256:b73f5a25818051c5eb6e4e1f17eee683973fac004872112e0f7d25f6538d31b0 Deleted: sha256:2c2e68719bb179679acd874d8006ba296701a9ebd3dc56222b9ff0bfb2616af5 Deleted: sha256:e582e3501440c7c3e94f5dd8e125c3efff2864b6f17353cbd14f0da925d756cb Deleted: sha256:8cd4c4c8cb47b88c28a3a18b4c03577240f0f5416009210e270e29a2da364cc1 Deleted: sha256:12e2bafa888d534a124dca677f4c3ada2d888350b786a7784e7999a0123e0b74 Untagged: test/cowsayimage:latest Deleted: sha256:e5a22e4037288055708bdd64be834c2ef6e4ebe972964fa6109f10d222d5429b Deleted: sha256:0c2f0c6ac672bbfd4a9a31ebf1dd9c37d5fd991a62c822e1cd0b25607eb23324 Untagged: ubuntu:latest Untagged: ubuntu@sha256:7a47ccc3bbe8a451b500d2b53104868b46d60ee8f5b35a24b41a86077c650210 Deleted: sha256:47b19964fb500f3158ae57f20d16d8784cc4af37c52c49d3b4f5bc5eede49541 Deleted: sha256:d4c69838355b876cd3eb0d92b4ef27b1839f5b094a4eb1ad2a1d747dd5d6088f Deleted: sha256:1c29a32189d8f2738d0d99378dc0912c9f9d289b52fb698bdd6c1c8cd7a33727 Deleted: sha256:d801a12f6af7beff367268f99607376584d8b2da656dcd8656973b7ad9779ab4 Deleted: sha256:bebe7ce6215aee349bee5d67222abeb5c5a834bbeaa2f2f5d05363d9fd68db41 Untagged: debian:wheezy Untagged: debian@sha256:62b635539e55e0ddadacb5ec5fb39ca1d89b8b0bd1b19e1fd516b7a0b2416137 Deleted: sha256:8c971baff57ba9c8cf39355e5b8e04981436bea82b28f1a55bf875d0f3d2ae06 Deleted: sha256:0e9f3c1de5b3836f41678653a8b16ebb3b1a2020cd1b0dc065b682a7a672b1f2 Untagged: debian:latest Untagged: debian@sha256:4fcd8c0b6f5e3bd44a3e63be259fd0c038476d432953d449ef34aedf16def331 Deleted: sha256:1b3ec9d977fb413627aca6244b27538013905167db25702a500474616ac2e3c8 Deleted: sha256:8568818b1f7f534832b393c531edfcb4a30e7eb40b573e68fdea90358987231f Untagged: centos:latest Untagged: centos@sha256:2671f7a3eea36ce43609e9fe7435ade83094291055f1c96d9d1d1d7c0b986a5d Deleted: sha256:ff426288ea903fcf8d91aca97460c613348f7a27195606b45f19ae91776ca23d Deleted: sha256:e15afa4858b655f8a5da4c4a41e05b908229f6fab8543434db79207478511ff7 Error: No such image: bbde42c4599c Error: No such image: 0273e5ec1af2 Error: No such image: 531b2b19d881 Error: No such image: 1e1762b7d427 Error: No such image: 1df45fbba7b4 Error: No such image: 91125e99f81e Error: No such image: 38b289fe568c Error response from daemon: conflict: unable to delete 83992f1037a6 (cannot be forced) - image has dependent child images Error: No such image: ec8a4ff13d1e Error: No such image: f58efd7b7bf2 Error: No such image: e57f146ec12b Error: No such image: 2c2e68719bb1 Error: No such image: 8cd4c4c8cb47 $ docker images -a REPOSITORY TAG IMAGE ID CREATED SIZE
Since we have been experimenting we have many images left behind. We use “docker rmi” to remove all images from our local repository. We have a clean local repository.
# **** log into repository (34) **** $ docker login Authenticating with existing credentials... WARNING! Your password will be stored unencrypted in /home/johncanessa/.docker/config.json. Configure a credential helper to remove this warning. See https://docs.docker.com/engine/reference/commandline/login/#credentials-store Login Succeeded
We login into the Docker Hub. Note you need to do this when you wish to use the Docker Hub repository.
# **** pull cowsay from the repository (35) **** $ docker pull johncanessa/cowsay Using default tag: latest latest: Pulling from johncanessa/cowsay 2eaed095b90d: Pull complete bc1ad329fa69: Pull complete 3783076db0a1: Pull complete Digest: sha256:98cdcc6365e9e61030bcaf035fa055d59007f3fd818861641a17dea0bffb1553 Status: Downloaded newer image for johncanessa/cowsay:latest $ docker images REPOSITORY TAG IMAGE ID CREATED SIZE johncanessa/cowsay latest 30d74744acb1 17 hours ago 131MB
We now pull the johncanessa/cowsay image and verify that a copy is found in our local repo.
# **** run the image we just downloaded (36) **** $ docker run johncanessa/cowsay ________________________________ < Tomorrow, you can be anywhere. > -------------------------------- \ ^__^ \ (oo)\_______ (__)\ )\/\ ||----w | || ||
When we run the image without adding text, cowsay displays a fortune message. The issue has been solved. Note that we did not have to push it to Docker Hub to make it work. This was just a way to kill two birds with one stone.
Now we will move to the final example using Redis and will try additional Docker features.
# **** Redis (37) **** https://en.wikipedia.org/wiki/Redis a key-value (disctionary) store written in ANCI C Has been around since 2009
Now that we know something about Redis, we will start with an image that has Redis already installed.
# **** pull latest redis image (38) **** $ docker pull redis Using default tag: latest latest: Pulling from library/redis 6ae821421a7d: Pull complete e3717477b42d: Pull complete 8e70bf6cc2e6: Pull complete 0f84ab76ce60: Pull complete 0903bdecada2: Pull complete 492876061fbd: Pull complete Digest: sha256:dd5b84ce536dffdcab79024f4df5485d010affa09e6c399b215e199a0dca38c4 Status: Downloaded newer image for redis:latest $ docker images -a REPOSITORY TAG IMAGE ID CREATED SIZE johncanessa/cowsay latest 30d74744acb1 22 hours ago 131MB redis latest 0f55cf3661e9 2 weeks ago 95MB
Using “docker pull” we get the Redis image. We then verify that it is in our local repository.
# **** run redis container in the background (39) **** --detach Run container in background and print container ID --name string Assign a name to the container $ docker run --name myredis -d redis 6eba1f137463439f56a54c1de774aa40b2e5f3f71a7e1201642fefa7dfcdd58a $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6eba1f137463 redis "docker-entrypoint.s…" 40 seconds ago Up 38 seconds 6379/tcp myredis
We will now run “docker run” with a couple additional arguments. We then verify that the container is up and running.
# **** display output from the logs of the container (40) **** $ docker logs myredis 1:C 26 Feb 2019 20:11:16.577 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo 1:C 26 Feb 2019 20:11:16.577 # Redis version=5.0.3, bits=64, commit=00000000, modified=0, pid=1, just started 1:C 26 Feb 2019 20:11:16.577 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf 1:M 26 Feb 2019 20:11:16.579 * Running mode=standalone, port=6379. 1:M 26 Feb 2019 20:11:16.579 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128. 1:M 26 Feb 2019 20:11:16.579 # Server initialized 1:M 26 Feb 2019 20:11:16.579 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect. 1:M 26 Feb 2019 20:11:16.579 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled. 1:M 26 Feb 2019 20:11:16.579 * Ready to accept connections
By using the “docker logs” command we can display the contents of the log for the container in question. Of interest is the port=6379 message that indicates that Redis is listening on that port for commands. We could download into our computer system redis-cli and used it to communicate with the Redis server running in the container. That takes time and we might not need the Redis CLI for later use. How about using a second container to communicate with the Redis server?
# **** start new container (41) **** --rm Automatically remove the container when it exits -i Keep STDIN open even if not attached -t Allocate a pseudo-TTY --link list Add link to another container $ docker run --rm -it --link myredis:redis redis /bin/bash
We start a second container and specify the –link (to be deprecated in the future, but for experimenting it is simple to use) option to be able to communicate with the Redis server.
# **** run redis-cli (42) **** root@ae1a14eaf7e4:/data# redis-cli -h redis -p 6379 redis:6379> ping PONG redis:6379> redis:6379> set "abc" 123 OK redis:6379> get "abc" "123" redis:6379> exit root@ae1a14eaf7e4:/data# exit exit
Since we started the service with a shell we can invoke the redis-cli to communicate with the specified host at the specified port. We verify that we can communicate with the Redis server and set and get a value pair. We then exit the redis-cli application and the container.
# **** backup the redis container (43)**** $ docker run --rm -it --link myredis:redis redis /bin/bash root@e09755c9171c:/data# redis-cli -h redis -p 6379 redis:6379> ping PONG redis:6379> set "abc" 123 OK redis:6379> set "xyz" 789 OK redis:6379> get "abc" "123" redis:6379> get "xyz" "789"
Our Redis server container is still up and running. We start the second container and expose the bash shell. We check that we are able to communicate with the Redis server. We set and get a couple value pairs. All seems to be working fine.
# **** save the redis dataset end exit the container (44) **** redis:6379> lastsave (integer) 1551219125 redis:6379> save OK redis:6379> lastsave (integer) 1551220166 redis:6379> bgsave Background saving started redis:6379> lastsave (integer) 1551220183 redis:6379> exit root@e09755c9171c:/data# exit exit
On the container running redis-cli we issue a set of Redis commands. The idea is to make a backup of the Redis database. When done we exit the shell and the container.
# **** check some arguments (45) **** --rm Automatically remove the container when it exits --volumes-from list Mount volumes from the specified container(s) -v, --volume list Bind mount a volume $ docker help cp Usage: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|- docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH Copy files/folders between a container and the local filesystem Options: -a, --archive Archive mode (copy all uid/gid information) -L, --follow-link Always follow symbol link in SRC_PATH $ docker run --rm --volumes-from myredis -v $PWD/backup:/backup debian cp /data/dump.rdb /backup/ Unable to find image 'debian:latest' locally latest: Pulling from library/debian 741437d97401: Pull complete Digest: sha256:066051f6674f6a3293bbd5a190081b1ae7fcae655a3884db59ebb3a2831da623 Status: Downloaded newer image for debian:latest
We now check some arguments by using “docker help” and run “docker run” to produce the dump.rdb file in our local file system.
# **** locate and dump the dump.rdb file (46) **** $ cd backup $ ls -l total 4 -rw-r--r--. 1 root root 112 Feb 26 16:39 dump.rdb $ xxd dump.rdb 0000000: 5245 4449 5330 3030 39fa 0972 6564 6973 REDIS0009..redis 0000010: 2d76 6572 0535 2e30 2e33 fa0a 7265 6469 -ver.5.0.3..redi 0000020: 732d 6269 7473 c040 fa05 6374 696d 65c2 s-bits.@..ctime. 0000030: d6bd 755c fa08 7573 6564 2d6d 656d c208 ..u\..used-mem.. 0000040: 040d 00fa 0c61 6f66 2d70 7265 616d 626c .....aof-preambl 0000050: 65c0 00fe 00fb 0200 0003 7879 7ac1 1503 e.........xyz... 0000060: 0003 6162 63c0 7bff bded e0b5 7ea9 118d ..abc.{.....~...
We locate the folder in which the dump was generated. We then dump the binary file. It seems that worked.
# **** stop and delete the container (47) **** $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6eba1f137463 redis "docker-entrypoint.s…" 3 hours ago Up 3 hours 6379/tcp myredis $ docker stop myredis myredis $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6eba1f137463 redis "docker-entrypoint.s…" 3 hours ago Exited (0) 5 seconds ago myredis
We stop and delete the container running the Redis server.
# **** remove all leftover containers (48) **** $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 6eba1f137463 redis "docker-entrypoint.s…" 3 hours ago Exited (0) 2 minutes ago myredis $ docker rm $(docker ps -aq) 6eba1f137463 $ docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
Since we are done experimenting, we can safely remove all leftover containers and images.
Hopefully this was helpful for you as it was for me. One needs to read and experiment in order to make sure that the concepts were understood.
If you have comments or questions regarding this or any other post in this blog please leave me a note bellow. The same holds true if you need assistance with your software development project.
Keep on learning, experimenting and having fun developing software.
John
Follow me on Twitter: @john_canessa