Merge pull request #1961 from deitch/compose-examples

add compose dynamic
This commit is contained in:
Justin Cormack 2017-06-04 16:25:04 +01:00 committed by GitHub
commit 982bddb185
11 changed files with 356 additions and 0 deletions

2
projects/compose/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
image-cache/
dist/

49
projects/compose/Makefile Normal file
View File

@ -0,0 +1,49 @@
.PHONY: tag push hash dynamic static cache-images run-static run-dynamic
ORG?=linuxkitprojects
IMAGE=compose
DEPS=image/Dockerfile docker-compose.yml image/waitfordocker.sh image/load-images-and-compose.sh
COMMON_IMAGES := \
nginx:alpine \
traefik
HASH?=$(shell git ls-tree HEAD -- ./image | awk '{print $$3}')
hash:
@echo ${HASH}
tag: $(DEPS)
docker build --squash --no-cache -t $(ORG)/$(IMAGE):$(HASH) image/
push: tag
DOCKER_CONTENT_TRUST=1 docker pull $(ORG)/$(IMAGE):$(HASH) || \
DOCKER_CONTENT_TRUST=1 docker push $(ORG)/$(IMAGE):$(HASH)
dynamic:
mkdir -p dist
moby build -name compose-dynamic -dir dist/ compose-dynamic.yml
static: cache-images
mkdir -p dist
moby build -name compose-static -dir dist/ compose-static.yml
run-dynamic:
linuxkit run dist/compose-dynamic
run-static:
linuxkit run dist/compose-static
clean:
rm -rf image-cache
image-cache/%.tar:
mkdir -p $(dir $@)
DOCKER_CONTENT_TRUST=1 docker image pull $(shell basename $@ .tar)
docker image save -o $@ $(shell basename $@ .tar)
# use make here for each image rather than a single for loop so we can cache dependencies
cache-images:
for image in $(COMMON_IMAGES) ; do \
make "image-cache/$${image}.tar" ; \
done

View File

@ -0,0 +1,57 @@
# Compose Project
The purpose of this project is to show how moby and linuxkit can be used to build a runnable linuxkit image with compose-style apps ready-to-run.
The apps are simple:
* nginx serving app A
* nginx serving app B
* traefik routing on the basis of hostname between apps A and B
## Compose Methods
We provide samples of two methods for using compose: dynamic and static.
Both methods use the image `linuxkit/compose`. The image does the following:
1. Wait for compose to be ready.
2. If there are any tar files available in `/images/*.tar`, treat them as tarred up docker images and load them into docker via `docker load ...`
3. Run `docker compose ...`
The only difference between dynamic and static is whether or not container images are pre-loaded in the linuxkit image.
* Compose: the `linuxkit/compose` image looks for a compose file at `/compose/docker-compose.yml`
* Images: the `linuxkit/compose` image looks for tarred container images at `/compose/images/*.tar`
### Dynamic
Dynamic loads the _compose_ config into the linuxkit image at build time. Container images are not pre-loaded, and thus docker loads the container images from the registry **at run-time**. This is no different than doing the following:
1. Using the docker linuxkit image
2. Connecting remotely via the docker API
3. Running the compose file remotely
Except that the compose is run at launch time, and there is no need for a remote connection to the docker API.
It works by loading the `docker-compose.yml` file onto the linuxkit image, and making it available to the `compose` container image via a bind-mount.
To build a dynamic image, do `make dynamic`. To run it, do `make run-dynamic`.
### Static
Static loads the _compose_ config **and** the container _images_ into the linuxkit image at build time. When run, docker loads the images from its local cache and does not depend on access to a registry.
It works by loading the `docker-compose.yml` file onto the linuxkit image and tarred up container image files. It then makes them available to the `compose` container image via bind-mounts.
To build a static image, do `make static`. To run it, do `make run-static`.
Static images pre-load them by doing:
1. Download the image locally `docker image pull <image>`
2. Save the image to a local tar file `docker image save -o <image> <imagename>.tar`
3. copy the tar file to the container image
4. When starting the container from the image with the files, load the images into docker before running compose: `docker image load -i <image> && rm -f <imagename>.tar`
### Conversion
A final option would be converting all of the containers defined in a `docker-compose.yml` into linuxkit `services`. It also would require setting up appropriate networks and other services provided by docker when running compose.
An example may be added in the future.

View File

@ -0,0 +1,56 @@
kernel:
image: "linuxkit/kernel:4.9.x"
cmdline: "console=ttyS0 page_poison=1"
init:
- linuxkit/init:1b8a7e394d2ec2f1fdb4d67645829d1b5bdca037
- linuxkit/runc:3a4e6cbf15470f62501b019b55e1caac5ee7689f
- linuxkit/containerd:b1766e4c4c09f63ac4925a6e4612852a93f7e73b
- linuxkit/ca-certificates:75cf419fb58770884c3464eb687ec8dfc704169d
onboot:
- name: sysctl
image: "linuxkit/sysctl:3aa6bc663c2849ef239be7d941d3eaf3e6fcc018"
- name: sysfs
image: linuxkit/sysfs:1244c5a86dfa2318c4e304af68d37e12367e1b7f
- name: dhcpcd
image: "linuxkit/dhcpcd:7d2b8aaaf20c24ad7d11a5ea2ea5b4a80dc966f1"
command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
- name: binfmt
image: "linuxkit/binfmt:8ac5535f57f0c6f5fe88317b9d22a7677093c765"
- name: format
image: "linuxkit/format:180cb2dc1de5e60373385080f8148abf10a3afac"
- name: mount
image: "linuxkit/mount:ff5338822f20375b8913f5a80f9ed4f6ea9a592b"
command: ["/mount.sh", "/var/lib/docker"]
services:
- name: rngd
image: "linuxkit/rngd:1fa4de44c961bb5075647181891a3e7e7ba51c31"
- name: ntpd
image: "linuxkit/openntpd:45deeb05f736162d941c9bf494983f655ab80aa5"
- name: docker
image: "linuxkit/docker-ce:668d62da6e3da081a8f8aca7db3e2a98adf5da59"
capabilities:
- all
net: host
mounts:
- type: cgroup
options: ["rw","nosuid","noexec","nodev","relatime"]
binds:
- /var/lib/docker:/var/lib/docker
- /lib/modules:/lib/modules
- /var/run:/var/run
- /var/html:/var/html
- name: compose
image: "linuxkitprojects/compose:0535e78608f57702745dfd56fbe78d28d237e469"
binds:
- /var/run:/var/run
- /var/compose:/compose
files:
- path: var/html/a/index.html
source: html-a.html
- path: var/html/b/index.html
source: html-b.html
- path: var/compose/docker-compose.yml
source: docker-compose.yml
trust:
org:
- linuxkit

View File

@ -0,0 +1,60 @@
kernel:
image: "linuxkit/kernel:4.9.x"
cmdline: "console=ttyS0 page_poison=1"
init:
- linuxkit/init:1b8a7e394d2ec2f1fdb4d67645829d1b5bdca037
- linuxkit/runc:3a4e6cbf15470f62501b019b55e1caac5ee7689f
- linuxkit/containerd:b1766e4c4c09f63ac4925a6e4612852a93f7e73b
- linuxkit/ca-certificates:75cf419fb58770884c3464eb687ec8dfc704169d
onboot:
- name: sysctl
image: "linuxkit/sysctl:3aa6bc663c2849ef239be7d941d3eaf3e6fcc018"
- name: sysfs
image: linuxkit/sysfs:1244c5a86dfa2318c4e304af68d37e12367e1b7f
- name: dhcpcd
image: "linuxkit/dhcpcd:7d2b8aaaf20c24ad7d11a5ea2ea5b4a80dc966f1"
command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"]
- name: binfmt
image: "linuxkit/binfmt:8ac5535f57f0c6f5fe88317b9d22a7677093c765"
- name: format
image: "linuxkit/format:180cb2dc1de5e60373385080f8148abf10a3afac"
- name: mount
image: "linuxkit/mount:ff5338822f20375b8913f5a80f9ed4f6ea9a592b"
command: ["/mount.sh", "/var/lib/docker"]
services:
- name: rngd
image: "linuxkit/rngd:1fa4de44c961bb5075647181891a3e7e7ba51c31"
- name: ntpd
image: "linuxkit/openntpd:45deeb05f736162d941c9bf494983f655ab80aa5"
- name: docker
image: "linuxkit/docker-ce:668d62da6e3da081a8f8aca7db3e2a98adf5da59"
capabilities:
- all
net: host
mounts:
- type: cgroup
options: ["rw","nosuid","noexec","nodev","relatime"]
binds:
- /var/lib/docker:/var/lib/docker
- /lib/modules:/lib/modules
- /var/run:/var/run
- /var/html:/var/html
- name: compose
image: "linuxkitprojects/compose:0535e78608f57702745dfd56fbe78d28d237e469"
binds:
- /var/run:/var/run
- /var/compose:/compose
files:
- path: var/html/a/index.html
source: html-a.html
- path: var/html/b/index.html
source: html-b.html
- path: var/compose/docker-compose.yml
source: docker-compose.yml
- path: var/compose/images/nginx:alpine.tar
source: image-cache/nginx:alpine.tar
- path: var/compose/images/traefik.tar
source: image-cache/traefik.tar
trust:
org:
- linuxkit

View File

@ -0,0 +1,25 @@
version: '2.1'
services:
a:
image: nginx:alpine
volumes:
- /var/html/a:/usr/share/nginx/html
labels:
- "traefik.backend=a"
- "traefik.frontend.rule=Host:a.docker.localhost"
b:
image: nginx:alpine
volumes:
- /var/html/b:/usr/share/nginx/html
labels:
- "traefik.backend=b"
- "traefik.frontend.rule=Host:b.docker.localhost"
- "traefik.port=80"
proxy:
image: traefik
command: --web --docker --docker.domain=docker.localhost --logLevel=DEBUG
ports:
- "80:80"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /dev/null:/traefik.toml

View File

@ -0,0 +1,8 @@
<html>
<head>
<title>A index</title>
</head>
<body>
This is the index for A
</body>
</html>

View File

@ -0,0 +1,8 @@
<html>
<head>
<title>B index</title>
</head>
<body>
This is the index for B
</body>
</html>

View File

@ -0,0 +1,27 @@
FROM docker/compose:1.13.0
# because compose requires all sorts of dynamic libs, including glibc, it is much easier to
# add docker client to compose than the reverse
ENV DOCKER_BUCKET get.docker.com
ENV DOCKER_VERSION 17.05.0-ce
ENV DOCKER_SHA256 340e0b5a009ba70e1b644136b94d13824db0aeb52e09071410f35a95d94316d9
# we need docker compose and docker load
# also need curl to test availability of docker API
RUN apk add --update curl
# we only need the client
RUN set -x \
&& curl -fSL "https://${DOCKER_BUCKET}/builds/Linux/x86_64/docker-${DOCKER_VERSION}.tgz" -o docker.tgz \
&& echo "${DOCKER_SHA256} *docker.tgz" | sha256sum -c - \
&& tar -xzvf docker.tgz \
&& mv docker/docker /usr/bin/ \
&& rm -rf docker docker.tgz \
&& docker -v
RUN mkdir -p /compose /app
WORKDIR /app
COPY . /app
ENTRYPOINT ["/app/waitfordocker.sh"]
CMD ["/app/load-images-and-compose.sh"]

View File

@ -0,0 +1,17 @@
#!/bin/sh
set -e
#########
#
# load any cached mounted images, and run compose
#
########
[ -n "$DEBUG" ] && set -x
for image in /compose/images/*.tar ; do
docker image load -i $image && rm -f $image
done
docker-compose -f /compose/docker-compose.yml up -d

View File

@ -0,0 +1,47 @@
#!/bin/sh
set -e
#########
#
# wait for docker socket to be ready, then run the rest of the command
#
########
RETRIES=${RETRIES:-"-1"}
WAIT=${WAIT:=10}
[ -n "$DEBUG" ] && set -x
# keep retrying until docker is ready or we hit our limut
retry_or_fail() {
local retry_count=0
local success=1
local cmd=$1
local retryMax=$2
local retrySleep=$3
local message=$4
until [[ $retry_count -ge $retryMax && $retryMax -ne -1 ]]; do
echo "trying to $message"
set +e
$cmd
success=$?
set -e
[[ $success == 0 ]] && break
retry_count=$(( $retry_count+1 )) || true
echo "attempt number $retry_count failed to $message, sleeping $retrySleep seconds..."
sleep $retrySleep
done
# did we succeed?
if [[ $success != 0 ]]; then
echo "failed to $message after $retryMax tries. Exiting..." >&2
exit 1
fi
}
connect_to_docker() {
[ -S /var/run/docker.sock ] || return 1
curl --unix-socket /var/run/docker.sock http://localhost/containers/json >/dev/null 2>&1 || return 1
}
# try to connect to docker
retry_or_fail connect_to_docker $RETRIES $WAIT "connect to docker"
# if we got here, we succeeded
$@