2017년 3월 28일 화요일

Dockerfile.ppc64le 알아보기

ppc64le/ubuntu 환경에서 원하는 버전의 Docker engine 을 사용하기 위해서, 직접 Docker 소스코드를 빌드하여 사용하는 방법이 있습니다.

이때 사용하게 되는 것이 Docker github에 이미 올라와 있는, 잘 만들어진 Dockerfile.ppc64le 입니다. 이 파일을 살펴보면, go lang, 등등의 버전을 원하는 대로 설정하여 Docker 엔진을 빌드하여 사용할 수 있습니다.

https://github.com/docker/docker/blob/master/Dockerfile.ppc64le

아래는 Dockerfile.ppc64le 내용입니다.


# This file describes the standard way to build Docker on ppc64le, using docker
#
# Usage:
#
# # Assemble the full dev environment. This is slow the first time.
# docker build -t docker -f Dockerfile.ppc64le .
#
# # Mount your source in an interactive container for quick testing:
# docker run -v `pwd`:/go/src/github.com/docker/docker --privileged -i -t docker bash
#
# # Run the test suite:
# docker run --privileged docker hack/make.sh test-unit test-integration-cli test-docker-py
#
# Note: AppArmor used to mess with privileged mode, but this is no longer
# the case. Therefore, you don't have to disable it anymore.
#

FROM ppc64le/debian:jessie

# allow replacing httpredir or deb mirror
ARG APT_MIRROR=deb.debian.org
RUN sed -ri "s/(httpredir|deb).debian.org/$APT_MIRROR/g" /etc/apt/sources.list

# Packaged dependencies
RUN apt-get update && apt-get install -y \
    apparmor \
    apt-utils \
    aufs-tools \
    automake \
    bash-completion \
    btrfs-tools \
    build-essential \
    cmake \
    createrepo \
    curl \
    dpkg-sig \
    git \
    iptables \
    jq \
    net-tools \
    libapparmor-dev \
    libcap-dev \
    libltdl-dev \
    libsystemd-journal-dev \
    libtool \
    mercurial \
    pkg-config \
    python-dev \
    python-mock \
    python-pip \
    python-websocket \
    xfsprogs \
    tar \
    vim-common \
    --no-install-recommends

# Get lvm2 source for compiling statically
ENV LVM2_VERSION 2.02.103
RUN mkdir -p /usr/local/lvm2 \
    && curl -fsSL "https://mirrors.kernel.org/sourceware/lvm2/LVM2.${LVM2_VERSION}.tgz" \
        | tar -xzC /usr/local/lvm2 --strip-components=1
# See https://git.fedorahosted.org/cgit/lvm2.git/refs/tags for release tags

# Fix platform enablement in lvm2 to support ppc64le properly
RUN set -e \
    && for f in config.guess config.sub; do \
        curl -fsSL -o "/usr/local/lvm2/autoconf/$f" "http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=$f;hb=HEAD"; \
    done
# "arch.c:78:2: error: #error the arch code needs to know about your machine type"

# Compile and install lvm2
RUN cd /usr/local/lvm2 \
    && ./configure \
        --build="$(gcc -print-multiarch)" \
        --enable-static_link \
    && make device-mapper \
    && make install_device-mapper
# See https://git.fedorahosted.org/cgit/lvm2.git/tree/INSTALL

# Install seccomp: the version shipped upstream is too old
ENV SECCOMP_VERSION 2.3.2
RUN set -x \
        && export SECCOMP_PATH="$(mktemp -d)" \
        && curl -fsSL "https://github.com/seccomp/libseccomp/releases/download/v${SECCOMP_VERSION}/libseccomp-${SECCOMP_VERSION}.tar.gz" \
                | tar -xzC "$SECCOMP_PATH" --strip-components=1 \
        && ( \
                cd "$SECCOMP_PATH" \
                && ./configure --prefix=/usr/local \
                && make \
                && make install \
                && ldconfig \
        ) \
        && rm -rf "$SECCOMP_PATH"


# Install Go
# 이 부분이 go language 버전을 설치하는 부분입니다. https://golang.org/dl/ 사이트에 가보면 현재 ppc64le용으로 version 1.8까지 나와있습니다. ENV GO_VERSION을 변경하면 원하는 버전으로 설치하게 됩니다. 현재는 1.7.5 버전으로 설치하게 되어 있습니다.
# NOTE: official ppc64le go binaries weren't available until go 1.6.4 and 1.7.4
ENV GO_VERSION 1.7.5
RUN curl -fsSL "https://golang.org/dl/go${GO_VERSION}.linux-ppc64le.tar.gz" \
    | tar -xzC /usr/local

ENV PATH /go/bin:/usr/local/go/bin:$PATH
ENV GOPATH /go

# Dependency for golint
ENV GO_TOOLS_COMMIT 823804e1ae08dbb14eb807afc7db9993bc9e3cc3
RUN git clone https://github.com/golang/tools.git /go/src/golang.org/x/tools \
    && (cd /go/src/golang.org/x/tools && git checkout -q $GO_TOOLS_COMMIT)

# Grab Go's lint tool
ENV GO_LINT_COMMIT 32a87160691b3c96046c0c678fe57c5bef761456
RUN git clone https://github.com/golang/lint.git /go/src/github.com/golang/lint \
    && (cd /go/src/github.com/golang/lint && git checkout -q $GO_LINT_COMMIT) \
    && go install -v github.com/golang/lint/golint

# Install two versions of the registry. The first is an older version that
# only supports schema1 manifests. The second is a newer version that supports
# both. This allows integration-cli tests to cover push/pull with both schema1
# and schema2 manifests.
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827
RUN set -x \
    && export GOPATH="$(mktemp -d)" \
    && git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
    && (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT") \
    && GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
        go build -o /usr/local/bin/registry-v2 github.com/docker/distribution/cmd/registry \
    && (cd "$GOPATH/src/github.com/docker/distribution" && git checkout -q "$REGISTRY_COMMIT_SCHEMA1") \
    && GOPATH="$GOPATH/src/github.com/docker/distribution/Godeps/_workspace:$GOPATH" \
        go build -o /usr/local/bin/registry-v2-schema1 github.com/docker/distribution/cmd/registry \
    && rm -rf "$GOPATH"

# Install notary and notary-server
ENV NOTARY_VERSION v0.5.0
RUN set -x \
    && export GOPATH="$(mktemp -d)" \
    && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
    && (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
    && GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
        go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
    && GOPATH="$GOPATH/src/github.com/docker/notary/vendor:$GOPATH" \
        go build -o /usr/local/bin/notary github.com/docker/notary/cmd/notary \
    && rm -rf "$GOPATH"

# Get the "docker-py" source so we can run their integration tests
ENV DOCKER_PY_COMMIT e2655f658408f9ad1f62abdef3eb6ed43c0cf324
RUN git clone https://github.com/docker/docker-py.git /docker-py \
    && cd /docker-py \
    && git checkout -q $DOCKER_PY_COMMIT \
    && pip install -r test-requirements.txt

# Set user.email so crosbymichael's in-container merge commits go smoothly
RUN git config --global user.email 'docker-dummy@example.com'

# Add an unprivileged user to be used for tests which need it
RUN groupadd -r docker
RUN useradd --create-home --gid docker unprivilegeduser

VOLUME /var/lib/docker
WORKDIR /go/src/github.com/docker/docker
ENV DOCKER_BUILDTAGS apparmor pkcs11 seccomp selinux

# Let us use a .bashrc file
RUN ln -sfv $PWD/.bashrc ~/.bashrc

# Register Docker's bash completion.
RUN ln -sv $PWD/contrib/completion/bash/docker /etc/bash_completion.d/docker

# Get useful and necessary Hub images so we can "docker load" locally instead of pulling
COPY contrib/download-frozen-image-v2.sh /go/src/github.com/docker/docker/contrib/
RUN ./contrib/download-frozen-image-v2.sh /docker-frozen-images \
    ppc64le/buildpack-deps:jessie@sha256:902bfe4ef1389f94d143d64516dd50a2de75bca2e66d4a44b1d73f63ddf05dda \
    ppc64le/busybox:latest@sha256:38bb82085248d5a3c24bd7a5dc146f2f2c191e189da0441f1c2ca560e3fc6f1b \
    ppc64le/debian:jessie@sha256:412845f51b6ab662afba71bc7a716e20fdb9b84f185d180d4c7504f8a75c4f91 \
    ppc64le/hello-world:latest@sha256:186a40a9a02ca26df0b6c8acdfb8ac2f3ae6678996a838f977e57fac9d963974
# See also "hack/make/.ensure-frozen-images" (which needs to be updated any time this list is)

# Install tomlv, vndr, runc, containerd, tini, docker-proxy
# Please edit hack/dockerfile/install-binaries.sh to update them.
COPY hack/dockerfile/binaries-commits /tmp/binaries-commits
COPY hack/dockerfile/install-binaries.sh /tmp/install-binaries.sh
RUN /tmp/install-binaries.sh tomlv vndr runc containerd tini proxy

# Wrap all commands in the "docker-in-docker" script to allow nested containers
ENTRYPOINT ["hack/dind"]

# Upload docker source
# 해당 Dockerfile로 빌드한 이미지로 컨테이너를 수행하면, 현재 경로(docker github를 local에 복제한 경로를 의도함)를 실행된 컨테이너에서 copy 하여 사용하도록 합니다.
# 예컨데.. 컨테이너를 bash로 수행하게 되면, root@컨테이너ID:/go/src/github.com/docker/docker# 로 시작됩니다.
COPY . /go/src/github.com/docker/docker

ppc64le 용으로 특정 버전의 Docker engine build 하기

이전 글에서는 Ubuntu(ppc64le) 에다가 이미 잘 만들어진 Docker 엔진을 받아 간단히 설치했습니다. 그런데 이미 Build 된 Docker engine들은 Docker의 최신 버전은 아니더군요..

이왕 Ubuntu 16.10 버전을 사용하는 김에, Docker engine 도 최신으로 사용해보고자 Docker master binary 사이트를 찾아보았습니다. Docker 최신 바이너리는 현재 17.05 인것 같네요.

ppc64le OS 버전에 맞는 Docker 빌드는 어떻게 하는가?
https://developer.ibm.com/recipes/tutorials/build-docker-ppc64le-on-power-linux/

IBM developer recipe에서 누군가 이미 친절하게 설명해 놓았습니다.

방법 1. Docker Master binary 사이트에서 ppc64le 버전의 파일을 다운로드 받고, /usr/bin에 있던 기존 docker 바이너리와 바꿔치기 합니다.

아래가 현재 사용중인 binaries 입니다.


wget으로 master.docker.org 에서 위의 파일과 같은 이름을 가진 ppc64le 버전을 받아옵니다.
# wget https://master.dockerproject.org/linux/ppc64le/docker && wget https://master.dockerproject.org/linux/ppc64le/docker-containerd && wget https://master.dockerproject.org/linux/ppc64le/docker-containerd-ctr && wget https://master.dockerproject.org/linux/ppc64le/docker-containerd-shim && wget https://master.dockerproject.org/linux/ppc64le/docker-init && wget https://master.dockerproject.org/linux/ppc64le/docker-proxy && wget https://master.dockerproject.org/linux/ppc64le/docker-runc && wget https://master.dockerproject.org/linux/ppc64le/dockerd
# service docker stop
# cp docker docker-containerd docker-containerd-ctr docker-containerd shim docker-init docker-proxy docker-runc dockerd /usr/bin
# service docker start
# docker version


방법 2.위 방법이 잘 되지 않으면, Docker 문서에서 설명하는 것처럼 소스 코드로 직접 Docker 엔진을 빌드합니다. 그러나, 공식 문서는 x86 기준이므로 ppc64le와는 절차가 조금 다릅니다.


방법2를 상세히 보면,
1. 우선 ppc64le Ubuntu OS에 이미 기존에 빌드된 이전 버전의 Docker 엔진을 설치합니다. (이전 포스트 참조)

2. 그 다음 github에서 Docker 소스코드를 Local 영역에 받아오고, 브랜치를 설정합니다.

#mkdir /tmp_downloads
#cd /tmp_downloads
#git clone https://github.com/docker/docker.git
#cd docker

#git branch // 마스터 branch 만들기


#git tag // 소스 버전 확인

#git checkout -b v17.03.0-ce v17.03.0-ce // -b 옵션으로 임의 branch 생성하며 작업할 브랜치 전환(v17.03.0-ce) => git tag로 확인한 소스 버전으로 체크아웃을 수행하면, 도커 엔진 이미지 빌드 후, hack/make.sh 를 수행할때 해당 버전으로 소스코드를 빌드한다고 합니다. go language 버전을 변경하고 싶은 경우, Dockerfile.ppc64le 파일에서 "ENV GO_VERSION 1.7.5" 부분을 수정하면 됩니다. 기본은 1.7.5 버전입니다. (https://golang.org/dl/ 에서 최신 버전의 go language 확인 가능)

3. 이미 github에 작성되어 있는 Dockerfile.ppc64le 를 이용해서 원하는 버전의 Docker-engine 이미지를 빌드합니다.
# docker build -t docker-build -f Dockerfile.ppc64le .
# docker images // docker-build라는 이름으로 새로 생성된 이미지 확인
(아래는 빌드 수행 후 완료된 화면..)



4. 새로 생성된 Docker-engine 이미지로 컨테이너를 하나 실행하고, 이 컨테이너 안에서 스크립트를 수행하여 받아온 소스코드를 빌드합니다. (docker github의 hack/make.sh 스크립트 수행, 시간이 좀 걸림.)
# docker run --privileged --rm -ti docker-build /bin/bash
root@컨테이너ID:/go/src/github.com/docker/docker# hack/make.sh binary
 (완료 메시지를 보면, bundles/17.03.0-ce/binary-client, bundles/17.03.0-ce/binary-daemon 경로에 바이너리 파일이 생성되었다고 나옵니다.)

5. 소스코드 빌드가 완료되면, bundles/latest/binary에 해당 버전의 Docker 바이너리가 생성됩니다. 앞서 git checkout으로 전환했던 브랜치, git tag 버전(17.03.0-ce)대로 만들어졌네요. 경로를 잘 알아둡니다. (containerID:/go/src/github.com/docker/docker/bundles/17.03.0-ce/binary-....)
컨테이너를 빠져나옵니다.(종료되지 않도록 ctrl+P 누르고 ctrl+Q로 빠져나옵니다)
컨테이너에 생성되어 있는 바이너리 파일을 호스트로 copy 합니다.
# docker cp containerID:/go/src/github.com/docker/docker/bundles/17.03.0-ce/binary-client [다운받을 Host 임의 경로]
# docker cp containerID:/go/src/github.com/docker/docker/bundles/17.03.0-ce/binary-daemon [다운받을 Host 임의 경로]
 
 

참고로, 호스트OS에서도 좀전에 컨테이너에서 생성한 파일을 확인할 수 있습니다. (8e9d891....로 시작되는 부분을 어떻게 확인해야 하는지는 잘 모르겠습니다.)

6. 새로 만들어진 바이너리를 /usr/bin에 넣어주고 Docker 데몬을 재수행합니다. Docker 버전이 바뀌었는지 체크하면 완료.
# service docker stop
# cp binary-client/관련파일 /usr/bin/
# cp binary-daemon/관련파일 /usr/bin/
# system docker start
# docker version


여기까지 ppc64le 용도로 특정 버전의 Docker engine build 하는 방법을 알아보았습니다.
사실.. 이미 빌드 된 Docker engine 특정 버전의 바이너리만 있다면 방법 1로 간단히 수행할수 있습니다. 원하는 버전의 바이너리가 없을 때, 혹은 ppc64le용 Docker engine 소스를 스스로 수정하여 빌드하고자 할때 사용 가능한 방법입니다.