Deploying play-with-docker.com on my machine

If you don't know what play-with-docker is, GO CHECK IT OUT NOW!
It is one of the Moby cool hacks winners! (The other one is FaaS by @alexellisuk - check my post about it here)

play-with-docker - PWD

So, what is Play With Docker?

Hacked by two Docker captains, Marcos Nils(@marcosnils) and Jonathan Leibiusky(@xetorthio), basically, Play with Docker is a Docker playground which you can run directly in your browser. With this, you have no excuse anymore to, well, not play with docker...

In the below screenshot I've deployed a local PWD, and in it you see a swarm of 5, (1 manager, 4 workers) running locally on my machine, with a stack deployed.

pwd-local

But I wanted mine too

If for whatever reason you want to deploy this on your hardware or VMs, you can (Give access to people via the browser on premises without AWS cost or whatnot), just follow along this quick and dirty post.

What I wanted to do is some Docker-inception. Have a PWD running in my local Swarm and in it a Swarm running LinuxKit :)

git clone https://github.com/franela/play-with-docker
cd play-with-docker/
docker pull franela/dind

sudo apt install golang-go

export GOPATH=$HOME/.go
go get -v -d -t ./...
docker-compose up

that's it!

Head over to http://localhost and you can start clicking "Add New Instance"

Let's try to deploy a stack onto it now:

Create an instance, you'll get a shell, then on it run:

docker swarm init --advertise-addr eth0

You'll get something like the below output:

To add a worker to this swarm, run the following command:

    docker swarm join \
    --token SWMTKN-1-31ovfkdk8wrna2y3igjzdfqhdm0e72ghksb7m441j1hxr1wtwh-81smoz5hu4mrdqzblrydjh86i \
    10.0.0.7:2377

You can join other workers in if you'd like. To do so, click "Add New Instance" again and paste the command in the shell to join your workers.

Then, let's deploy our monitoring stack, which basically has portainer.io and manomarks/visualizer:

curl -o docker-compose-stack-monitoring.yml \
https://raw.githubusercontent.com/jmkhael/compose-samples/master/docker-compose-stack-monitoring.yml

docker stack deploy -c docker-compose-stack-monitoring.yml monitoring
docker stack ps monitoring

and here you'll see that the services are up and running!

ID            NAME                    IMAGE                        NODE   DESIRED STATE  CURRENT STATE           ERROR  PORTS
qjqciab49qqa  monitoring_viz.1        manomarks/visualizer:latest  node5  Running        Running 30 minutes ago
ske7lcocg8v6  monitoring_portainer.1  portainer/portainer:latest   node5  Running        Running 32 minutes ago
[node5] (local) root@10.0.0.7 ~

Sweet! It took me much more time to write this blog than to have play-for-docker deployed locally!

Bonus

Basically, I want to build the redis os from the keynote in PWD from the Moby cool hack!

Beyond this point, you are left alone in the Docker inception world...

Prepare LinuxKit

apk update
apk upgrade
apk add --no-cache go
export GOPATH=~/.go
go get -v -d -t ./...  

git clone https://github.com/linuxkit/linuxkit
cd linuxkit
make

Snipped output below:

mkdir -p bin
tar cf - vendor src/initrd src/pad4 -C src/cmd/moby . | docker run --rm --net=none --log-driver=none -i  linuxkit/go-compile:4513068d9a7e919e4ec42e2d7ee879ff5b95b7f5@sha256:bdfadbe3e4ec699ca45b67453662321ec270f2d1a1dbdbf09625776d3ebd68c5 --package github.com/linuxkit/linuxkit --ldflags "-X main.GitCommit=22514db912b9bec73e2a3c3ffd1611633c25b9db -X main.Version="0.0" " -o bin/moby > tmp_moby_bin.tar
Unable to find image 'linuxkit/go-compile:4513068d9a7e919e4ec42e2d7ee879ff5b95b7f5@sha256:bdfadbe3e4ec699ca45b67453662321ec270f2d1a1dbdbf09625776d3ebd68c5' locally
sha256:bdfadbe3e4ec699ca45b67453662321ec270f2d1a1dbdbf09625776d3ebd68c5: Pulling from linuxkit/go-compile
627beaf3eaaf: Pulling fs layer
...
49418cbb2668: Pull complete
Digest: sha256:bdfadbe3e4ec699ca45b67453662321ec270f2d1a1dbdbf09625776d3ebd68c5
Status: Downloaded newer image for linuxkit/go-compile@sha256:bdfadbe3e4ec699ca45b67453662321ec270f2d1a1dbdbf09625776d3ebd68c5
gofmt...
govet...
golint...
ineffassign...
go build...
...
gofmt...
govet...
golint...
ineffassign...
go build...
tar xf tmp_linuxkit_bin.tar > bin/linuxkit
rm tmp_linuxkit_bin.tar
touch bin/linuxkit

If all goes well, you'll have two binaries created under bin directory: moby and linuxkit. As per this pr:

  • moby: just does the simple build case,
  • linuxkit: is useful to push and run the constructed image
jmkhael@jmkhael-lx:~/workspace/linuxkit
$ ls bin/
linuxkit  moby

I've had to patch the Makefile so it works in PWD (It worked without modifications on my local machine directly. as per the previous post)
I've cheated a bit. I've added -v /root/.go:/go to the Docker run command for GO_COMPILE to have the dependencies.

Building the Redis OS sample project

So, let's make our OS:

make
./bin/moby build projects/demo/redis-os/redis-os

output of the command:

Extract kernel image: linuxkit/kernel:4.9.x
Add init containers:
Process init image: linuxkit/init:63eed9ca7a09d2ce4c0c5e7238ac005fa44f564b
Process init image: linuxkit/runc:b0fb122e10dbb7e4e45115177a61a3f8d68c19a9
Process init image: linuxkit/containerd:18eaf72f3f4f9a9f29ca1951f66df701f873060b
Add onboot containers:
Add service containers:
  Create OCI config for linuxkit/dhcpcd:0d4012269cb142972fed8542fbdc3ff5a7b695cd
  Create OCI config for redis:3.0.7-alpine
Add files:
Create outputs:
  redis-os-bzImage redis-os-initrd.img redis-os-cmdline

Testing the Redis OS

For that, just execute linuxkit run with the image. This will leverage qemu (on Linux) to run your OS in a VM! On Mac, all this given by moby/HyperKit. - note that as of the time of writing, Hyperkit only supports Mac.

"HyperKit is a toolkit for embedding hypervisor capabilities in your application. Supported backends are:
gcp
hyperkit [macOS]
qemu [linux]
vmware
packet"

Note that if you want to access the machine from outside, make sure to set the ip for the VM:

bin/linuxkit run redis-os

After a very short wait, you'll see a shell!

Let's abuse netcat to test redis-server from the image itself:

(printf "PING\r\n"; sleep 1) | nc localhost 6379
+PONG
(echo PING; sleep 1) | nc localhost 6379
+PONG

If you want to connect from the host machine,(where you built the os-redis image), you need to pass additional parameters for linuxkit/qemu runner (introduced by this pull request)

linuxkit run qemu -publish 6379:6379/tcp redis-os

You can then run on the host:

(printf "PING\r\n"; sleep 1) | nc localhost 6379
+PONG
(echo PING; sleep 1) | nc localhost 6379
+PONG

Enjoy your redis-os built by LinuxKit in PWD in Docker!

Diagnostics

If you need to diagnose why stuff are not working, netshoot docker image can save your day!

docker run -it --net host nicolaka/netshoot

and in it, run for instance tcpdump:

tcpdump -s 65535 tcp port 6379 -i any

and see the magic happens:

13:34:20.880434 IP localhost.38050 > localhost.6379: Flags [S], seq 3409053076, win 43690, options [mss 65495,sackOK,TS val 239977870 ecr 0,nop,wscale 7], length 0
13:34:20.880447 IP localhost.6379 > localhost.38050: Flags [S.], seq 195769136, ack 3409053077, win 43690, options [mss 65495,sackOK,TS val 239977870 ecr 239977870,nop,wscale 7], length 0
13:34:20.880458 IP localhost.38050 > localhost.6379: Flags [.], ack 1, win 342, options [nop,nop,TS val 239977870 ecr 239977870], length 0
13:34:20.880487 IP localhost.38050 > localhost.6379: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 239977870 ecr 239977870], length 5: RESP "PING"
13:34:20.880493 IP localhost.6379 > localhost.38050: Flags [.], ack 6, win 342, options [nop,nop,TS val 239977870 ecr 239977870], length 0
13:34:20.881104 IP localhost.6379 > localhost.38050: Flags [P.], seq 1:8, ack 6, win 342, options [nop,nop,TS val 239977870 ecr 239977870], length 7: RESP "PONG"
13:34:20.881112 IP localhost.38050 > localhost.6379: Flags [.], ack 8, win 342, options [nop,nop,TS val 239977870 ecr 239977870], length 0
13:34:21.880774 IP localhost.38050 > localhost.6379: Flags [F.], seq 6, ack 8, win 342, options [nop,nop,TS val 239978120 ecr 239977870], length 0
13:34:21.881299 IP localhost.6379 > localhost.38050: Flags [F.], seq 8, ack 7, win 342, options [nop,nop,TS val 239978121 ecr 239978120], length 0
13:34:21.881319 IP localhost.38050 > localhost.6379: Flags [.], ack 9, win 342, options [nop,nop,TS val 239978121 ecr 239978121], length 0

Cleaning up

When ready, and you want to stop this Redis OS, type halt in the VM shell. Notice that it takes more time to shutdown than to boot!

You can also kill linuxkit ;)

You should also remove the PWD running containers...

Next

Now, how can I put SwarmKit to handle a hierarchical Swarms built in PWD built on Docker? My head hurt now... and I have a flight to catch!

Au revoir Austin! Keep Austin weird!