Skip to content

Commit

Permalink
build/contrib: Improve docker support.
Browse files Browse the repository at this point in the history
This significantly reworks the docker support to provide build a
lightweight non-root distroless container image based on scratch.  It
employs a multi-stage build that downloads and builds the latest source
code, compresses the resulting binaries, and then produces the final
image based on scratch that only includes the Decred-specific binaries.

It must be noted that there are some still remaining TODO items in the
documentation as well as the Dockerfile that will need to be handled by
a future commit, but the changes are being submitted now to allow
another contributor to finish up those aspects.

The following is an overview of the changes:

- Removes existing Dockerfile and Dockerfile.alpine
- Introduces a new Dockerfile under contrib/docker with the following
  properties:
  - Runs as a non-root user
  - Uses a static UID:GID of 10000:10000
    - Note that using UIDs/GIDs below 10000 for container users is a
      security risk on several systems since a hypothetical attack which
      allows escalation outside of the container might otherwise
      coincide with an existing user's UID or existing group's GID which
      has additional permissions
  - The image is based on scratch image (aka completely empty) and only
    includes the Decred-specific binaries which means there is no shell
    or any other binaries available if an attacker were to somehow
    manage to find a remote execution vulnerability exploit in a Decred
    binary
- Introduces code to build an entrypoint for the image since it is based
  on scratch and thus has no shell for that purpose
- Adds contrib/docker/README.md
- Updates README.md in the main directory to account for changes
  - There is still outstanding work to be done here and thus has several
    TODOs
- Updates contrib/README.md to call out the new addition
  • Loading branch information
davecgh committed Sep 10, 2021
1 parent 598bf66 commit a4d793c
Show file tree
Hide file tree
Showing 7 changed files with 430 additions and 150 deletions.
48 changes: 0 additions & 48 deletions Dockerfile

This file was deleted.

55 changes: 0 additions & 55 deletions Dockerfile.alpine

This file was deleted.

69 changes: 22 additions & 47 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ https://decred.org/downloads/
```sh
$ git version
```

</details>
<details><summary><b>Windows Example</b></summary>

Expand Down Expand Up @@ -184,52 +183,28 @@ https://decred.org/downloads/
Run the `dcrd` executable now installed in `$GOPATH/bin`.
</details>

## Docker

### Running dcrd

You can run a decred node from inside a docker container. To build the image
yourself, use the following command:

```
docker build -t decred/dcrd .
```
Or you can create an alpine based image (requires Docker 17.05 or higher):
```
docker build -t decred/dcrd:alpine -f Dockerfile.alpine .
```
You can then run the image using:
```
docker run decred/dcrd
```
You may wish to use an external volume to customize your config and persist the
data in an external volume:
```
docker run --rm -v /home/user/dcrdata:/root/.dcrd/data decred/dcrd
```
For a minimal image, you can use the decred/dcrd:alpine tag. This is typically
a more secure option while also being a much smaller image.
You can run `dcrctl` from inside the image. For example, run an image (mounting
your data from externally) with:
```
docker run --rm -ti --name=dcrd-1 -v /home/user/.dcrd:/root/.dcrd \
decred/dcrd:alpine
```
And then run `dcrctl` commands against it. For example:
```
docker exec -ti dcrd-1 dcrctl getbestblock
```
## Building and Running OCI Containers (aka Docker/Podman)

The project does not officially provide container images. However, all of the
necessary files to build your own lightweight non-root container image based on
`scratch` from the latest source code are available in
[contrib/docker](./contrib/docker/README.md).

It is also worth noting that, to date, most users typically prefer to run `dcrd`
directly, without using a container, for at least a few reasons:

- `dcrd` is a static binary that does not require root privileges and therefore
does not suffer from the usual deployment issues that typically make
containers attractive
- It is harder and more verbose to run `dcrd` from a container as compared to
normal:
- `dcrd` is designed to automatically create a working default configuration
which means it just works out of the box without the need for additional
configuration for almost all typical users
- The blockchain data and configuration files need to be persistent which
means configuring and managing a docker data volume
- Running non-root containers with `docker` requires special care in regards
to permissions

## Running Tests

Expand Down
7 changes: 7 additions & 0 deletions contrib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,10 @@ if desired.

See the full [Simulation Network Reference](../docs/simnet_environment.mediawiki)
for more details.

### Building and Running OCI Containers (aka Docker/Podman)

The project does not officially provide container images. However, all of the
necessary files to build your own lightweight non-root container image based on
`scratch` from the latest source code are available in the docker directory.
See [docker/README.md](./docker/README.md) for more details.
83 changes: 83 additions & 0 deletions contrib/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@

# TODO: Needs some documentation here about the RPC server, logging via docker
# logs, mounting a volume, the conf file, etc...

###############
# Builder Stage
###############

# Basic Go environment with git, SSL CA certs, and upx.
# golang:1.17.1-alpine (linux/amd64)
FROM golang@sha256:13919fb9091f6667cb375d5fdf016ecd6d3a5d5995603000d422b04583de4ef9 AS builder
RUN apk add --no-cache git ca-certificates upx

# Empty directory to be copied into place in the production image since it will
# run as a non-root container and thus not have permissions to create
# directories or change ownership of anything outside of the structure already
# created for it.
RUN mkdir /emptydatadir

# New unprivileged user for use in production image below to improve security.
ENV USER=decred
ENV UID=10000
RUN adduser \
--disabled-password \
--gecos "" \
--home="/home/${USER}" \
--shell "/sbin/nologin" \
--no-create-home \
--uid "${UID}" \
"${USER}"

# Build dcrd and other commands it provides
WORKDIR /go/src/github.com/decred/dcrd
RUN git clone https://github.com/decred/dcrd . && \
CGO_ENABLED=0 GOOS=linux \
go install -trimpath -tags safe,netgo,timetzdata \
-ldflags="-s -w" \
. ./cmd/gencerts ./cmd/promptsecret

# Build dcrctl
WORKDIR /go/src/github.com/decred/dcrctl
RUN git clone https://github.com/decred/dcrctl . && \
CGO_ENABLED=0 GOOS=linux \
go install -trimpath -tags safe,netgo -ldflags="-s -w"

# Build entrypoint helper for the production image.
WORKDIR /go/src/github.com/decred/dcrd/contrib/docker/entrypoint
COPY ./contrib/docker/entrypoint/entrypoint.go .
RUN go mod init entrypoint && \
go mod tidy && \
CGO_ENABLED=0 GOOS=linux \
go install -trimpath -tags netgo,timetzdata -ldflags="-s -w" .

# Compress bins
RUN upx -9 /go/bin/*

##################
# Production image
##################

# Minimal scratch-based environment.
FROM scratch
ENV DECRED_DATA=/home/decred
#ENV DCRD_EXPOSE_RPC=false # TODO: Want something like this?
ENV DCRD_NO_FILE_LOGGING=true
COPY --from=builder /etc/passwd /etc/passwd
COPY --from=builder /etc/group /etc/group
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /go/bin/* /bin/
COPY --from=builder --chown=decred /emptydatadir /tmp

# Use an unprivileged user.
USER decred

# Ports for the p2p and json-rpc of mainnet, testnet, and simnet, respectively.
EXPOSE 9108 9109 19108 19109 18555 19556

ENTRYPOINT [ "/bin/entrypoint" ]

RUN [ "dcrd", "--version" ]

# TODO: Want this or not? I've seen conflicting info and I'm not a docker expert...
#VOLUME [ "/home/decred" ]
Loading

0 comments on commit a4d793c

Please sign in to comment.