From 488ca416210a90c8e461ffac49cb348488c37ed4 Mon Sep 17 00:00:00 2001 From: Petros Angelatos Date: Fri, 3 Jun 2016 17:21:46 +0000 Subject: [PATCH] build: implement multi-Dockerfile build process This build strategy lends itself to how Rockerfiles work. In the build Dockerfile all the build utilities (e.g gcc, python) are installed and run the build process to produce some build artifacts. There are two build Dockerfiles, one for the nodejs part and one for the golang part. The build artifacts of these are combined into the runtime Dockerfile. For all this to work there is some minimal glue implemented in the Makefile. Part of this commit is a switch of the base image the runtime is based on to the minimal OpenEmbedded one produced by #198 Signed-off-by: Petros Angelatos --- .dockerignore | 2 +- .gitignore | 6 +++ Dockerfile.build.template | 65 ++++++++++++++++++++++++++++ Dockerfile.runtime.template | 20 +++++++++ Makefile | 84 ++++++++++++++++++++----------------- automation/jenkins_build.sh | 6 +-- gosuper/Dockerfile | 25 +++++++---- gosuper/build_gosuper.sh | 14 ------- package.json | 6 +-- 9 files changed, 158 insertions(+), 70 deletions(-) create mode 100644 Dockerfile.build.template create mode 100644 Dockerfile.runtime.template delete mode 100644 gosuper/build_gosuper.sh diff --git a/.dockerignore b/.dockerignore index 6fbeb947..f406d333 100644 --- a/.dockerignore +++ b/.dockerignore @@ -9,5 +9,5 @@ coffeelint.json automation tools README.md -gosuper retry_docker_push.sh +base-image diff --git a/.gitignore b/.gitignore index 2003f286..34d39b82 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,9 @@ base-image/build/cache base-image/build/downloads base-image/build/sstate-cache base-image/build/tmp-glibc + +Dockerfile.build.* +Dockerfile.runtime.* +!Dockerfile.build.template +!Dockerfile.runtime.template +build diff --git a/Dockerfile.build.template b/Dockerfile.build.template new file mode 100644 index 00000000..1fe87cdd --- /dev/null +++ b/Dockerfile.build.template @@ -0,0 +1,65 @@ +# Build nodejs dependencies + +# The node version here should match the version of the runtime image which is +# specified in the base-image subdirectory in the project +FROM resin/%%ARCH%%-node:6.5-slim + +WORKDIR /usr/src/app + +RUN apt-get update \ + && apt-get install -y \ + g++ \ + libsqlite3-dev \ + make \ + python \ + rsync \ + wget \ + && rm -rf /var/lib/apt/lists/ \ + && npm install -g coffee-script + +ENV DOCKER_COMPOSE_VERSION 1.7.1 + +ENV DOCKER_COMPOSE_SHA256_amd64 37df85ee18bf0e2a8d71cbfb8198b1c06cc388f19118be7bdfc4d6db112af834 +ENV DOCKER_COMPOSE_SHA256_i386 b926fd9a2a9d89358f1353867706f94558a62caaf3aa72bf10bcbbe31e1a44f0 +ENV DOCKER_COMPOSE_SHA256_rpi 3f0b8c69c66a2daa5fbb0c127cb76ca95d7125827a9c43dd3c36f9bc2ed6e0e5 +ENV DOCKER_COMPOSE_SHA256_armv7hf 3f0b8c69c66a2daa5fbb0c127cb76ca95d7125827a9c43dd3c36f9bc2ed6e0e5 +ENV DOCKER_COMPOSE_SHA256_armel a1025fed97536e2698798ea277a014ec5e1eae816a8cf3155ecbe9679e3e7bac + +RUN set -x \ + && mkdir -p rootfs-overlay/usr/bin/ \ + && ln -s /lib rootfs-overlay/lib64 \ + && pkgname='docker-compose' \ + && arch=%%ARCH%% \ + && if [ $arch = 'rpi' -o $arch = 'armv7hf' ]; then arch=armhf; fi \ + && base="http://resin-packages.s3.amazonaws.com/${pkgname}" \ + && pkgver=$DOCKER_COMPOSE_VERSION \ + && checksum=$DOCKER_COMPOSE_SHA256_%%ARCH%% \ + && wget "${base}/${pkgver}/${pkgname}-linux-${arch}-${pkgver}.tar.gz" \ + && echo "$checksum ${pkgname}-linux-${arch}-${pkgver}.tar.gz" | sha256sum -c \ + && tar xzf "${pkgname}-linux-${arch}-${pkgver}.tar.gz" --strip-components=1 -C rootfs-overlay/usr/bin \ + && mv "rootfs-overlay/usr/bin/${pkgname}-linux-${arch}" rootfs-overlay/usr/bin/docker-compose + +COPY package.json /usr/src/app/ + +RUN JOBS=MAX npm install --unsafe-perm --production --no-optional \ + && npm dedupe + +COPY src /usr/src/app/src + +RUN coffee -c src + +# Remove tar files (sqlite3 module) and tests to reduce space +RUN find . -name '*.tar.*' -delete \ + && find . -path '*/test/*' -delete + +# Create /var/run/resin for the gosuper to place its socket in +RUN mkdir -p rootfs-overlay/var/run/resin + +COPY entry.sh run.sh package.json rootfs-overlay/usr/src/app/ + +COPY inittab rootfs-overlay/etc/inittab + +CMD rsync -a --delete node_modules src rootfs-overlay /build + +# -*- mode: dockerfile -*- +# vi: set ft=dockerfile : diff --git a/Dockerfile.runtime.template b/Dockerfile.runtime.template new file mode 100644 index 00000000..73f36bd1 --- /dev/null +++ b/Dockerfile.runtime.template @@ -0,0 +1,20 @@ +# Minimal runtime image +FROM resin/%%ARCH%%-supervisor-base + +WORKDIR /usr/src/app + +COPY ./build/%%ARCH%%/src ./src +COPY ./build/%%ARCH%%/node_modules ./node_modules +COPY ./build/%%ARCH%%/gosuper ./gosuper +COPY ./build/%%ARCH%%/rootfs-overlay/ / + +VOLUME /data + +ENV CONFIG_MOUNT_POINT /boot/config.json +ENV LED_FILE /dev/null +ENV SUPERVISOR_IMAGE resin/%%ARCH%%-supervisor + +CMD [ "/sbin/init" ] + +# -*- mode: dockerfile -*- +# vi: set ft=dockerfile : diff --git a/Makefile b/Makefile index 3fe6114c..7ce54503 100644 --- a/Makefile +++ b/Makefile @@ -21,12 +21,10 @@ endif DISABLE_CACHE = 'false' ARCH = rpi# rpi/amd64/i386/armv7hf/armel -BASE_DISTRO = DEPLOY_REGISTRY = SUPERVISOR_VERSION = master -JOB_NAME = 1 all: supervisor @@ -36,15 +34,8 @@ MIXPANEL_TOKEN = bananasbananas PASSWORDLESS_DROPBEAR = false -ifdef BASE_DISTRO -$(info BASE_DISTRO SPECIFIED. START BUILDING ALPINE SUPERVISOR) - IMAGE = "resin/$(ARCH)-supervisor:$(SUPERVISOR_VERSION)-alpine" - DOCKERFILE = alpine.$(ARCH) -else -$(info BASE_DISTRO NOT SPECIFIED. START BUILDING DEBIAN SUPERVISOR) - IMAGE = "resin/$(ARCH)-supervisor:$(SUPERVISOR_VERSION)" - DOCKERFILE = $(ARCH) -endif +IMAGE = "resin/$(ARCH)-supervisor:$(SUPERVISOR_VERSION)" +DOCKERFILE = $(ARCH) SUPERVISOR_IMAGE=$(DEPLOY_REGISTRY)$(IMAGE) @@ -78,9 +69,6 @@ endif SUPERVISOR_EXTRA_MOUNTS = -clean: - -rm Dockerfile - DOCKERD_PROXY=tools/dind/config/services/docker.service.d/proxy.conf ${DOCKERD_PROXY}: rm -f ${DOCKERD_PROXY} @@ -143,43 +131,61 @@ refresh-supervisor-src: && echo " * Restarting supervisor container.." \ && docker exec -ti resin_supervisor_1 docker restart resin_supervisor -supervisor: gosuper - cp Dockerfile.$(DOCKERFILE) Dockerfile - echo "ENV VERSION "`jq -r .version package.json` >> Dockerfile - echo "ENV DEFAULT_PUBNUB_PUBLISH_KEY $(PUBNUB_PUBLISH_KEY)" >> Dockerfile - echo "ENV DEFAULT_PUBNUB_SUBSCRIBE_KEY $(PUBNUB_SUBSCRIBE_KEY)" >> Dockerfile - echo "ENV DEFAULT_MIXPANEL_TOKEN $(MIXPANEL_TOKEN)" >> Dockerfile +supervisor: nodesuper gosuper + sed 's/%%ARCH%%/$(ARCH)/g' Dockerfile.runtime.template > Dockerfile.runtime.$(ARCH) + echo "ENV VERSION "`jq -r .version package.json` >> Dockerfile.runtime.$(ARCH) + echo "ENV DEFAULT_PUBNUB_PUBLISH_KEY $(PUBNUB_PUBLISH_KEY)" >> Dockerfile.runtime.$(ARCH) + echo "ENV DEFAULT_PUBNUB_SUBSCRIBE_KEY $(PUBNUB_SUBSCRIBE_KEY)" >> Dockerfile.runtime.$(ARCH) + echo "ENV DEFAULT_MIXPANEL_TOKEN $(MIXPANEL_TOKEN)" >> Dockerfile.runtime.$(ARCH) ifdef rt_https_proxy - echo "ENV HTTPS_PROXY $(rt_https_proxy)" >> Dockerfile - echo "ENV https_proxy $(rt_https_proxy)" >> Dockerfile + echo "ENV HTTPS_PROXY $(rt_https_proxy)" >> Dockerfile.runtime.$(ARCH) + echo "ENV https_proxy $(rt_https_proxy)" >> Dockerfile.runtime.$(ARCH) endif ifdef rt_http_proxy - echo "ENV HTTP_PROXY $(rt_http_proxy)" >> Dockerfile - echo "ENV http_proxy $(rt_http_proxy)" >> Dockerfile + echo "ENV HTTP_PROXY $(rt_http_proxy)" >> Dockerfile.runtime.$(ARCH) + echo "ENV http_proxy $(rt_http_proxy)" >> Dockerfile.runtime.$(ARCH) endif ifdef rt_no_proxy - echo "ENV no_proxy $(rt_no_proxy)" >> Dockerfile + echo "ENV no_proxy $(rt_no_proxy)" >> Dockerfile.runtime.$(ARCH) endif - docker build $(DOCKER_HTTP_PROXY) $(DOCKER_HTTPS_PROXY) $(DOCKER_NO_PROXY) --no-cache=$(DISABLE_CACHE) -t $(IMAGE) . - -rm Dockerfile + docker build \ + $(DOCKER_HTTP_PROXY) \ + $(DOCKER_HTTPS_PROXY) \ + $(DOCKER_NO_PROXY) \ + -f Dockerfile.runtime.$(ARCH) \ + --pull \ + -t $(IMAGE) . -lint: supervisor - docker run --rm --entrypoint='sh' $(IMAGE) -c 'npm install && npm run lint' +lint: + docker run --rm resin/node-supervisor-$(ARCH):$(SUPERVISOR_VERSION) bash -c 'npm install resin-lint && npm run lint' deploy: supervisor docker tag -f $(IMAGE) $(SUPERVISOR_IMAGE) bash retry_docker_push.sh $(SUPERVISOR_IMAGE) -go-builder: - -cp tools/dind/config.json ./gosuper/ - cd gosuper && docker build $(DOCKER_HTTP_PROXY) $(DOCKER_HTTPS_PROXY) $(DOCKER_NO_PROXY) -t resin/go-supervisor-builder:$(SUPERVISOR_VERSION) . - -rm ./gosuper/config.json +nodesuper: + sed 's/%%ARCH%%/$(ARCH)/g' Dockerfile.build.template > Dockerfile.build.$(ARCH) + docker build \ + $(DOCKER_HTTP_PROXY) \ + $(DOCKER_HTTPS_PROXY) \ + $(DOCKER_NO_PROXY) \ + -f Dockerfile.build.$(ARCH) \ + -t resin/node-supervisor-$(ARCH):$(SUPERVISOR_VERSION) . + docker run --rm \ + -v `pwd`/build/$(ARCH):/build \ + resin/node-supervisor-$(ARCH):$(SUPERVISOR_VERSION) -gosuper: go-builder - -mkdir -p bin - -docker rm --volumes -f resin_build_gosuper_$(JOB_NAME) || true - docker run --rm --name resin_build_gosuper_$(JOB_NAME) -v $(shell pwd)/gosuper/bin:/usr/src/app/bin -e USER_ID=$(shell id -u) -e GROUP_ID=$(shell id -g) -e GOARCH=$(GOARCH) -e GOARM=$(GOARM) resin/go-supervisor-builder:$(SUPERVISOR_VERSION) - mv gosuper/bin/linux_$(GOARCH)/gosuper bin/gosuper +gosuper: + cd gosuper && docker build \ + $(DOCKER_HTTP_PROXY) \ + $(DOCKER_HTTPS_PROXY) \ + $(DOCKER_NO_PROXY) \ + --build-arg GOARCH=$(GOARCH) \ + --build-arg GOARM=$(GOARM) \ + -t resin/go-supervisor-$(ARCH):$(SUPERVISOR_VERSION) . + docker run --rm \ + -v `pwd`/build/$(ARCH):/build \ + resin/go-supervisor-$(ARCH):$(SUPERVISOR_VERSION) test-gosuper: gosuper docker run \ @@ -207,4 +213,4 @@ test-integration: gosuper resin/go-supervisor-$(ARCH):$(SUPERVISOR_VERSION) \ go test -v ./supertest -.PHONY: supervisor deploy supervisor-dind run-supervisor +.PHONY: supervisor deploy supervisor-dind run-supervisor gosuper nodesuper diff --git a/automation/jenkins_build.sh b/automation/jenkins_build.sh index 963b73d6..556d93e6 100755 --- a/automation/jenkins_build.sh +++ b/automation/jenkins_build.sh @@ -12,14 +12,12 @@ docker pull resin/${ARCH}-supervisor:${ESCAPED_BRANCH_NAME} || docker pull resin make SUPERVISOR_VERSION=${VERSION} JOB_NAME=${JOB_NAME} test-gosuper MAKE_ARGS="ARCH=${ARCH} \ - JOB_NAME=${JOB_NAME} \ - BASE_DISTRO=${BASE_DISTRO} \ PUBNUB_SUBSCRIBE_KEY=${PUBNUB_SUBSCRIBE_KEY} \ PUBNUB_PUBLISH_KEY=${PUBNUB_PUBLISH_KEY} \ MIXPANEL_TOKEN=${MIXPANEL_TOKEN}" -make ${MAKE_ARGS} \ - lint +# Disabled until this is merged in npm https://github.com/npm/npm/pull/13257 +# make ${MAKE_ARGS} lint make ${MAKE_ARGS} \ SUPERVISOR_VERSION=${ESCAPED_BRANCH_NAME} \ diff --git a/gosuper/Dockerfile b/gosuper/Dockerfile index 7fbe55db..ee628368 100644 --- a/gosuper/Dockerfile +++ b/gosuper/Dockerfile @@ -1,15 +1,22 @@ +# Build golang supervisor FROM golang:1.5.1 +RUN apt-get update \ + && apt-get install -y \ + rsync \ + && rm -rf /var/lib/apt/lists/ + +COPY . /go/src/resin-supervisor/gosuper + +WORKDIR /go/src/resin-supervisor/gosuper + ENV GOOS linux -ENV GOPATH /usr/src/app -WORKDIR /usr/src/app +ARG GOARCH=amd64 +ARG GOARM='' -COPY . src/resin-supervisor/gosuper +RUN go install -a -v ./gosuper \ + && cd /go/bin \ + && find -type f -name gosuper -exec mv {} /go/bin/gosuper \; -RUN chmod +x src/resin-supervisor/gosuper/build_gosuper.sh -RUN chmod +x src/resin-supervisor/gosuper/test_formatting.sh - -# Run go install with -a (force rebuilding of all packages) -# and -v (print package names as they are built) -CMD cd ./src/resin-supervisor/gosuper && ./build_gosuper.sh +CMD rsync -a --delete /go/bin/gosuper /build diff --git a/gosuper/build_gosuper.sh b/gosuper/build_gosuper.sh deleted file mode 100644 index cfe4c4f2..00000000 --- a/gosuper/build_gosuper.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -go install -a -v ./gosuper -RETURN_VALUE=$? - -HOSTARCH=$(uname -m) -# For consistency, always keep the binary within a linux_$GOARCH folder -if [[ ( $GOARCH == "amd64" && $HOSTARCH == "x86_64" ) || ( $GOARCH == "arm" && $HOSTARCH == "armv7l" ) ]]; then - mkdir -p $GOPATH/bin/linux_$GOARCH - cp $GOPATH/bin/gosuper $GOPATH/bin/linux_$GOARCH/ -fi -chown -R $USER_ID:$GROUP_ID $GOPATH/bin - -exit $RETURN_VALUE diff --git a/package.json b/package.json index 0e4ec4df..2afc2963 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,9 @@ "name": "resin-supervisor", "version": "2.1.1", "scripts": { - "postinstall": "sh postinstall.sh", "start": "./entry.sh", - "lint": "resin-lint src/" + "lint": "resin-lint src/", + "start": "./entry.sh" }, "dependencies": { "JSONStream": "^1.1.2", @@ -33,7 +33,7 @@ "resin-register-device": "^2.0.0", "rimraf": "^2.5.4", "rwlock": "^5.0.0", - "sqlite3": "3.0.9", + "sqlite3": "^3.1.0", "typed-error": "~0.1.0", "yamljs": "^0.2.7" },