diff --git a/.dockerignore b/.dockerignore index 4cabd9531f7..7f6bbbfe91f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,3 +1,5 @@ +Dockerfile +Dockerfile.fast .git/ !.git/HEAD !.git/refs/ diff --git a/Dockerfile b/Dockerfile index c8c95e1fdd0..28151056bcd 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM alpine:edge +FROM golang:1.9-stretch MAINTAINER Lars Gierth # There is a copy of this Dockerfile called Dockerfile.fast, @@ -6,6 +6,51 @@ MAINTAINER Lars Gierth # # Please keep these two Dockerfiles in sync. +ENV GX_IPFS "" +ENV SRC_DIR /go/src/github.com/ipfs/go-ipfs + +COPY . $SRC_DIR + +# Build the thing. +RUN cd $SRC_DIR \ + # Required for getting the HEAD commit hash via git rev-parse. + && mkdir .git/objects \ + # Allows using a custom (i.e. local) IPFS API endpoint. + && ([ -z "$GX_IPFS" ] || echo $GX_IPFS > /root/.ipfs/api) \ + # Build the thing. + && make build + +ENV SUEXEC_VERSION v0.2 +ENV TINI_VERSION v0.16.1 +RUN set -x \ + # Get su-exec, a very minimal tool for dropping privileges + && cd /tmp \ + && git clone https://github.com/ncopa/su-exec.git \ + && cd su-exec \ + && git checkout -q $SUEXEC_VERSION \ + && make \ + # Get tini, a very minimal init daemon for containers + && cd /tmp \ + && wget -q -O tini https://github.com/krallin/tini/releases/download/$TINI_VERSION/tini \ + && chmod +x tini + +# Get the TLS CA certificates, they're not provided by busybox. +RUN apt-get install -y ca-certificates + +# Now comes the actual target image, which aims to be as small as possible. +FROM busybox:1-glibc +MAINTAINER Lars Gierth + +# Get the ipfs binary, entrypoint script, and TLS CAs from the build container. +ENV SRC_DIR /go/src/github.com/ipfs/go-ipfs +COPY --from=0 $SRC_DIR/cmd/ipfs/ipfs /usr/local/bin/ipfs +COPY --from=0 $SRC_DIR/bin/container_daemon /usr/local/bin/start_ipfs +COPY --from=0 /tmp/su-exec/su-exec /sbin/su-exec +COPY --from=0 /tmp/tini /sbin/tini +COPY --from=0 /etc/ssl/certs /etc/ssl/certs + +# This shared lib (part of glibc) doesn't seem to be included with busybox. +COPY --from=0 /lib/x86_64-linux-gnu/libdl-2.24.so /lib/libdl.so.2 # Ports for Swarm TCP, Swarm uTP, API, Gateway, Swarm Websockets EXPOSE 4001 @@ -14,51 +59,19 @@ EXPOSE 5001 EXPOSE 8080 EXPOSE 8081 -# IPFS API to use for fetching gx packages. -# This can be a gateway too, since its read-only API provides all gx needs. -# - e.g. /ip4/172.17.0.1/tcp/8080 if the Docker host -# has the IPFS gateway listening on the bridge interface -# provided by Docker's default networking. -# - if empty, the public gateway at ipfs.io is used. -ENV GX_IPFS "" -# The IPFS fs-repo within the container +# Create the fs-repo directory and switch to a non-privileged user. ENV IPFS_PATH /data/ipfs -# The default logging level -ENV IPFS_LOGGING "" -# Golang stuff -ENV GOPATH /go -ENV PATH /go/bin:$PATH -ENV SRC_PATH /go/src/github.com/ipfs/go-ipfs +RUN mkdir -p $IPFS_PATH \ + && adduser -D -h $IPFS_PATH -u 1000 -g 100 ipfs \ + && chown 1000:100 $IPFS_PATH # Expose the fs-repo as a volume. -# start_ipfs initializes an fs-repo if none is mounted +# start_ipfs initializes an fs-repo if none is mounted. +# Important this happens after the USER directive so permission are correct. VOLUME $IPFS_PATH -# Get the go-ipfs sourcecode -COPY . $SRC_PATH - -RUN apk add --no-cache --virtual .build-deps-ipfs musl-dev gcc go git \ - && apk add --no-cache tini su-exec bash wget ca-certificates \ - # Setup user - && adduser -D -h $IPFS_PATH -u 1000 ipfs \ - # Install gx - && go get -u github.com/whyrusleeping/gx \ - && go get -u github.com/whyrusleeping/gx-go \ - # Point gx to a specific IPFS API - && ([ -z "$GX_IPFS" ] || echo $GX_IPFS > $IPFS_PATH/api) \ - # Invoke gx - && cd $SRC_PATH \ - && gx --verbose install --global \ - && mkdir .git/objects && commit=$(git rev-parse --short HEAD) \ - && echo "ldflags=-X github.com/ipfs/go-ipfs/repo/config.CurrentCommit=$commit" \ - # Build and install IPFS and entrypoint script - && cd $SRC_PATH/cmd/ipfs \ - && go build -ldflags "-X github.com/ipfs/go-ipfs/repo/config.CurrentCommit=$commit" \ - && cp ipfs /usr/local/bin/ipfs \ - && cp $SRC_PATH/bin/container_daemon /usr/local/bin/start_ipfs \ - && chmod 755 /usr/local/bin/start_ipfs \ - # Remove all build-time dependencies - && apk del --purge .build-deps-ipfs && rm -rf $GOPATH && rm -vf $IPFS_PATH/api +# The default logging level +ENV IPFS_LOGGING "" # This just makes sure that: # 1. There's an fs-repo, and initializes one if there isn't. diff --git a/Dockerfile.fast b/Dockerfile.fast index ea659354484..9668fa46498 100644 --- a/Dockerfile.fast +++ b/Dockerfile.fast @@ -1,4 +1,4 @@ -FROM alpine:edge +FROM golang:1.9-stretch MAINTAINER Lars Gierth # This is a copy of /Dockerfile, @@ -6,50 +6,72 @@ MAINTAINER Lars Gierth # # Please keep these two Dockerfiles in sync. +ENV GX_IPFS "" +ENV SRC_DIR /go/src/github.com/ipfs/go-ipfs +COPY ./package.json $SRC_DIR/package.json + +RUN set -x \ + && go get github.com/whyrusleeping/gx \ + && go get github.com/whyrusleeping/gx-go \ + # Allows using a custom (i.e. local) IPFS API endpoint. + && ([ -z "$GX_IPFS" ] || echo $GX_IPFS > /root/.ipfs/api) \ + # Fetch the dependencies so we don't have to do it everytime. + && cd $SRC_DIR \ + && gx install + +COPY . $SRC_DIR + +# Build the thing. +RUN set -x \ + && cd $SRC_DIR \ + # Required for getting the HEAD commit hash via git rev-parse. + && mkdir .git/objects \ + # Build the thing. + && make build \ + && mv cmd/ipfs/ipfs /usr/local/bin/ipfs \ + && mv bin/container_daemon /usr/local/bin/start_ipfs + +ENV SUEXEC_VERSION v0.2 +ENV TINI_VERSION v0.16.1 +RUN set -x \ + # Get su-exec, a very minimal tool for dropping privileges + && cd /tmp \ + && git clone https://github.com/ncopa/su-exec.git \ + && cd su-exec \ + && git checkout -q $SUEXEC_VERSION \ + && make \ + # Get tini, a very minimal init daemon for containers + && cd /tmp \ + && wget -q -O tini https://github.com/krallin/tini/releases/download/$TINI_VERSION/tini \ + && chmod +x tini \ + # Install them + && mv su-exec/su-exec tini /sbin/ + +# Ports for Swarm TCP, Swarm uTP, API, Gateway, Swarm Websockets EXPOSE 4001 EXPOSE 4002/udp EXPOSE 5001 EXPOSE 8080 +EXPOSE 8081 -ENV GX_IPFS "" +# Create the fs-repo directory and switch to a non-privileged user. ENV IPFS_PATH /data/ipfs -ENV IPFS_LOGGING "" -ENV GOPATH /go -ENV PATH /go/bin:$PATH -ENV SRC_PATH /go/src/github.com/ipfs/go-ipfs +RUN mkdir -p $IPFS_PATH \ + && useradd -s /usr/sbin/nologin -d $IPFS_PATH -u 1000 -g 100 ipfs \ + && chown 1000:100 $IPFS_PATH +# Expose the fs-repo as a volume. +# start_ipfs initializes an fs-repo if none is mounted. VOLUME $IPFS_PATH -# This is an optimization which avoids rebuilding -# of the gx dependencies every time anything changes. -# gx will only be invoked if the dependencies have changed. -# -# Put differently: if package.json has changed, -# the image-id after this COPY command will change, -# and trigger a re-run of all following commands. -COPY ./package.json $SRC_PATH/package.json - -RUN apk add --no-cache --virtual .build-deps-ipfs musl-dev gcc go git \ - && apk add --no-cache tini su-exec bash wget ca-certificates \ - && adduser -D -h $IPFS_PATH -u 1000 ipfs \ - && go get -u github.com/whyrusleeping/gx \ - && go get -u github.com/whyrusleeping/gx-go \ - && ([ -z "$GX_IPFS" ] || echo $GX_IPFS > $IPFS_PATH/api) \ - && cd $SRC_PATH \ - && gx --verbose install --global - -COPY . $SRC_PATH - -RUN cd $SRC_PATH \ - && mkdir .git/objects && commit=$(git rev-parse --short HEAD) \ - && echo "ldflags=-X github.com/ipfs/go-ipfs/repo/config.CurrentCommit=$commit" \ - && cd $SRC_PATH/cmd/ipfs \ - && go build -ldflags "-X github.com/ipfs/go-ipfs/repo/config.CurrentCommit=$commit" \ - && cp ipfs /usr/local/bin/ipfs \ - && cp $SRC_PATH/bin/container_daemon /usr/local/bin/start_ipfs \ - && chmod 755 /usr/local/bin/start_ipfs \ - && apk del --purge .build-deps-ipfs && rm -rf $GOPATH && rm -vf $IPFS_PATH/api +# The default logging level +ENV IPFS_LOGGING "" +# This just makes sure that: +# 1. There's an fs-repo, and initializes one if there isn't. +# 2. The API and Gateway are accessible from outside the container. ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/start_ipfs"] + +# Execute the daemon subcommand by default CMD ["daemon", "--migrate=true"] diff --git a/bin/container_daemon b/bin/container_daemon old mode 100644 new mode 100755 index 04d1a9a4270..ff8f88dbbcb --- a/bin/container_daemon +++ b/bin/container_daemon @@ -4,6 +4,7 @@ user=ipfs repo="$IPFS_PATH" if [ `id -u` -eq 0 ]; then + echo "Changing user to $user" # ensure folder is writable su-exec "$user" test -w "$repo" || chown -R -- "$user" "$repo" # restart script with new privileges diff --git a/test/sharness/t0301-docker-migrate.sh b/test/sharness/t0301-docker-migrate.sh index e6c9a078923..b6c105d289a 100755 --- a/test/sharness/t0301-docker-migrate.sh +++ b/test/sharness/t0301-docker-migrate.sh @@ -69,7 +69,7 @@ test_expect_success "kill the net cat" ' ' test_expect_success "correct version was requested" ' - grep "/fs-repo-migrations/v1.1.1/fs-repo-migrations_v1.1.1_linux-musl-amd64.tar.gz" dist_serv_out > /dev/null + grep "/fs-repo-migrations/v1.1.1/fs-repo-migrations_v1.1.1_linux-amd64.tar.gz" dist_serv_out > /dev/null ' test_done