Skip to content

Commit 5463682

Browse files
Adding support for production grade image in Dockerfile (#180)
I have modified the current Dockerfile to be able to generate a Production grade Docker Image based on UBI, the new Dockerfile follows the below good practices for Production. Multi-stage build: keeps the final image small and clean. Non-root execution: creates appuser (uid 10001) and runs the service as non-root. Minimal runtime dependencies: no extra tools/packages installed (keeps attack surface small). Metadata labels: provides traceability (name, version, maintainer, vendor, etc.). Deterministic build: dependencies are pulled in the build stage, final image only has the binary. Absolute path: in ENTRYPOINT: safer for production. --------- Signed-off-by: Anushka <[email protected]> Signed-off-by: pco <[email protected]> Co-authored-by: pco <[email protected]>
1 parent 9199b20 commit 5463682

File tree

8 files changed

+96
-17
lines changed

8 files changed

+96
-17
lines changed

.github/workflows/ci.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,14 @@ name: CI
66

77
on:
88
push:
9-
branches: [ "**" ]
9+
branches: ["**"]
1010
pull_request:
11-
branches: [ "**" ]
11+
branches: ["**"]
1212

1313
env:
1414
DB_DEPLOYMENT: local
1515

1616
jobs:
17-
1817
lint:
1918
name: Lint and Build
2019
runs-on: ubuntu-latest

.github/workflows/docker-release.yml

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,10 @@ jobs:
6363
- name: Build cross-architecture binaries
6464
run: make build-arch build-test-genesis-block
6565

66-
- name: Set image prefix
66+
- name: Set image build prefix and metadata
6767
run: |
68+
echo "CREATED=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> $GITHUB_ENV
69+
echo "REVISION=$(git rev-parse HEAD)" >> $GITHUB_ENV
6870
if [ "$GITHUB_REPOSITORY_OWNER" == "hyperledger" ]; then
6971
echo "IMAGE_PREFIX=hyperledger" >> $GITHUB_ENV
7072
else
@@ -88,9 +90,12 @@ jobs:
8890
BIN=committer
8991
ARCHBIN_PATH=archbin
9092
PORTS=4001 2114 9001 2119 5001 2115 6001 2116 7001 2117
93+
VERSION=${{ env.VERSION }}
94+
CREATED=${{ env.CREATED }}
95+
REVISION=${{ env.REVISION }}
9196
cache-from: type=registry,ref=docker.io/${{ env.IMAGE_PREFIX }}/fabric-x-committer:buildcache
9297
cache-to: type=registry,ref=docker.io/${{ env.IMAGE_PREFIX }}/fabric-x-committer:buildcache,mode=max
93-
98+
9499
- name: Build and Push Multi-Platform Docker Image for Loadgen
95100
uses: docker/build-push-action@v6
96101
with:
@@ -107,6 +112,9 @@ jobs:
107112
BIN=loadgen
108113
ARCHBIN_PATH=archbin
109114
PORTS=8001 2118
115+
VERSION=${{ env.VERSION }}
116+
CREATED=${{ env.CREATED }}
117+
REVISION=${{ env.REVISION }}
110118
cache-from: type=registry,ref=docker.io/${{ env.IMAGE_PREFIX }}/fabric-x-loadgen:buildcache
111119
cache-to: type=registry,ref=docker.io/${{ env.IMAGE_PREFIX }}/fabric-x-loadgen:buildcache,mode=max
112120

@@ -124,5 +132,8 @@ jobs:
124132
ghcr.io/${{ env.GHCR_PREFIX }}/fabric-x-committer-test-node:latest
125133
build-args: |
126134
ARCHBIN_PATH=archbin
135+
VERSION=${{ env.VERSION }}
136+
CREATED=${{ env.CREATED }}
137+
REVISION=${{ env.REVISION }}
127138
cache-from: type=registry,ref=docker.io/${{ env.IMAGE_PREFIX }}/fabric-x-committer-test-node:buildcache
128139
cache-to: type=registry,ref=docker.io/${{ env.IMAGE_PREFIX }}/fabric-x-committer-test-node:buildcache,mode=max

Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
#########################
2222

2323
go_cmd ?= go
24-
version := 0.0.2
24+
version := latest
2525
project_dir := $(shell dirname $(realpath $(firstword $(MAKEFILE_LIST))))
2626
output_dir ?= $(project_dir)/bin
2727
arch_output_dir ?= $(project_dir)/archbin
@@ -43,7 +43,7 @@ cmd ?=
4343
# An error will occur if neither container engine is installed.
4444
docker_cmd ?= $(shell command -v docker >/dev/null 2>&1 && echo docker || \
4545
echo podman || { echo "Error: Neither Docker nor Podman is installed." >&2; exit 1; })
46-
image_namespace=icr.io/cbdc
46+
image_namespace=docker.io/hyperledger
4747

4848
# Set these parameters to compile to a specific os/arch
4949
# E.g., make build-local os=linux arch=amd64

docker/images/release/Dockerfile

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,55 @@
1+
#
12
# Copyright IBM Corp. All Rights Reserved.
23
#
34
# SPDX-License-Identifier: Apache-2.0
45
#
5-
FROM registry.access.redhat.com/ubi9/ubi-micro:9.4 AS prod
6+
7+
###########################################
8+
# Stage 1: Production runtime image
9+
###########################################
10+
FROM registry.access.redhat.com/ubi9/ubi-minimal:9.6 AS prod
11+
612
ARG BIN
713
ARG ARCHBIN_PATH
8-
ARG PORTS
914
ARG TARGETOS
1015
ARG TARGETARCH
16+
ARG PORTS
17+
18+
# Label args
19+
ARG VERSION=1.0
20+
ARG CREATED
21+
ARG REVISION=1.0
1122

23+
# Add non-root user (10001) using BIN argument
24+
RUN /usr/sbin/useradd -u 10001 -r -g root -s /sbin/nologin -c "Hyperledger Fabric-X ${BIN} user" ${BIN} && \
25+
mkdir -p /home/${BIN} && \
26+
chown -R 10001:0 /home/${BIN} && \
27+
chmod 0755 /home/${BIN}
28+
29+
# Copy binaries
1230
COPY ${ARCHBIN_PATH}/${TARGETOS}-${TARGETARCH}/${BIN} /bin/${BIN}
31+
32+
# Create fixed entrypoint since args are not replaced
33+
# within ENTRYPOINT or CMD
34+
RUN ln -s /bin/${BIN} /bin/entrypoint
35+
36+
# Expose ports
1337
EXPOSE ${PORTS}
38+
39+
# OCI metadata labels
40+
LABEL org.opencontainers.image.created="${CREATED}" \
41+
org.opencontainers.image.description="Hyperledger Fabric-X ${BIN} packaged in a UBI image." \
42+
org.opencontainers.image.licenses="Apache-2.0" \
43+
org.opencontainers.image.ref.name="ubi9/ubi-minimal" \
44+
org.opencontainers.image.revision="${REVISION}" \
45+
org.opencontainers.image.source="https://github.com/hyperledger/fabric-x-committer" \
46+
org.opencontainers.image.title="fabric-x-${BIN}" \
47+
org.opencontainers.image.url="https://github.com/hyperledger/fabric-x-committer" \
48+
org.opencontainers.image.version="${VERSION}"
49+
50+
# Use non-root user and set workdir using BIN argument
51+
USER 10001
52+
WORKDIR /home/${BIN}
53+
54+
# Default Entrypoint
55+
ENTRYPOINT ["/bin/entrypoint"]

docker/images/test_node/Dockerfile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
1+
#
12
# Copyright IBM Corp. All Rights Reserved.
23
#
34
# SPDX-License-Identifier: Apache-2.0
45
#
6+
7+
###########################################
8+
# Stage 1: Production runtime image
9+
###########################################
510
FROM postgres:16.9-alpine3.21 AS node
611

712
ARG ARCHBIN_PATH
813
ARG TARGETOS
914
ARG TARGETARCH
15+
ARG VERSION
1016

1117
ENV CONFIGS_PATH=/root/config
1218
ENV BINS_PATH=/root/bin
@@ -33,6 +39,19 @@ COPY ./cmd/config/samples $CONFIGS_PATH
3339
COPY ./bin/sc-genesis-block.proto.bin $CONFIGS_PATH/
3440
RUN chmod a+x ${BINS_PATH}/*
3541

42+
# Expose ports
3643
EXPOSE 7050 4001 2114 7001 2117 2110
3744

45+
# OCI metadata labels
46+
LABEL org.opencontainers.image.created="${CREATED}" \
47+
org.opencontainers.image.description="Hyperledger Fabric-X Committer Test Node." \
48+
org.opencontainers.image.licenses="Apache-2.0" \
49+
org.opencontainers.image.ref.name="postgres" \
50+
org.opencontainers.image.revision="${REVISION}" \
51+
org.opencontainers.image.source="https://github.com/hyperledger/fabric-x-committer" \
52+
org.opencontainers.image.title="fabric-x-committer-test-node" \
53+
org.opencontainers.image.url="https://github.com/hyperledger/fabric-x-committer" \
54+
org.opencontainers.image.version="${VERSION}"
55+
56+
# Default CMD
3857
CMD ["run"]

docker/test/common.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,10 @@ func (p *startNodeParameters) asNode(node string) startNodeParameters {
5050
}
5151

5252
const (
53-
channelName = "mychannel"
54-
monitoredMetric = "loadgen_transaction_committed_total"
55-
testNodeImage = "icr.io/cbdc/committer-test-node:0.0.2"
53+
channelName = "mychannel"
54+
monitoredMetric = "loadgen_transaction_committed_total"
55+
containerPrefixName = "sc_test"
56+
testNodeImage = "docker.io/hyperledger/committer-test-node:latest"
5657
)
5758

5859
func createAndStartContainerAndItsLogs(

docker/test/container_release_image_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ import (
2828
)
2929

3030
const (
31-
committerReleaseImage = "icr.io/cbdc/committer:0.0.2"
32-
loadgenReleaseImage = "icr.io/cbdc/loadgen:0.0.2"
31+
committerReleaseImage = "docker.io/hyperledger/fabric-x-committer:latest"
32+
loadgenReleaseImage = "docker.io/hyperledger/fabric-x-loadgen:latest"
3333
networkPrefixName = test.DockerNamesPrefix + "_network"
3434
genBlockFile = "sc-genesis-block.proto.bin"
3535
// containerConfigPath is the path to the config directory inside the container.
@@ -179,16 +179,18 @@ func startCommitterNodeWithReleaseImage(ctx context.Context, t *testing.T, param
179179
t.Helper()
180180

181181
configPath := filepath.Join(containerConfigPath, params.node)
182+
containerUser := "0:0"
183+
t.Logf("Starting %s as container with user %s.\n", committerReleaseImage, containerUser)
182184
createAndStartContainerAndItsLogs(ctx, t, createAndStartContainerParameters{
183185
config: &container.Config{
184186
Image: committerReleaseImage,
185187
Cmd: []string{
186-
"committer",
187188
fmt.Sprintf("start-%s", params.node),
188189
"--config",
189190
fmt.Sprintf("%s.yaml", configPath),
190191
},
191192
Hostname: params.node,
193+
User: containerUser,
192194
Env: []string{
193195
"SC_COORDINATOR_SERVER_TLS_MODE=" + params.tlsMode,
194196
"SC_COORDINATOR_VERIFIER_TLS_MODE=" + params.tlsMode,
@@ -225,16 +227,18 @@ func startLoadgenNodeWithReleaseImage(
225227
t.Helper()
226228

227229
configPath := filepath.Join(containerConfigPath, params.node)
230+
containerUser := "0:0"
231+
t.Logf("Starting %s as container with user %s.\n", loadgenReleaseImage, containerUser)
228232
createAndStartContainerAndItsLogs(ctx, t, createAndStartContainerParameters{
229233
config: &container.Config{
230234
Image: loadgenReleaseImage,
231235
Cmd: []string{
232-
params.node,
233236
"start",
234237
"--config",
235238
fmt.Sprintf("%s.yaml", configPath),
236239
},
237240
Hostname: params.node,
241+
User: containerUser,
238242
ExposedPorts: nat.PortSet{
239243
loadGenMetricsPort + "/tcp": {},
240244
},

scripts/build-release-image.sh

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,16 @@ function build_image() {
1818
local image_name=$1
1919
local bin=$2
2020
local service_ports=$3
21-
local manifest_name=${namespace}/${image_name}:${version}
21+
local manifest_name=${namespace}/fabric-x-${image_name}:${version}
2222
local cmd=(
2323
"${docker_cmd}" build
2424
-f "${dockerfile_release_dir}/Dockerfile"
2525
--build-arg BIN="${bin}"
2626
--build-arg PORTS="${service_ports}"
2727
--build-arg ARCHBIN_PATH="${arch_bin_dir}"
28+
--build-arg VERSION="${version}"
29+
--build-arg CREATED="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
30+
--build-arg REVISION="$(git rev-parse HEAD)"
2831
)
2932

3033
if [ "${multiplatform}" = true ]; then

0 commit comments

Comments
 (0)