Skip to content

Commit 0e9a38d

Browse files
authored
feat(proxy, proxy-init): Combine proxy and proxy-init and use minimal base image (#14577)
To simplify the docker images we ship, we combine the proxy and proxy-init images into a unified image (named proxy) which includes both the proxy and proxy-init binaries. To reduce the security surface area of this unified image, we build it on a minimal Wolfi-based runtime image via apko instead of building on `gcr.io/distroless/cc-debian12`. This allows us to avoid including unused packages such as `libssl` which can cause spurious security scan alerts in our images. In order to build this minimal runtime base image in CI, we start a local temporary registry so that we can push the apko created runtime image and use it as a base image for the proxy image. We update the Linkerd templates to use this new unified proxy image in the linkerd-init container. Signed-off-by: Alex Leong <[email protected]>
1 parent 91df299 commit 0e9a38d

File tree

83 files changed

+383
-423
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+383
-423
lines changed

.github/actions/docker-build/action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,15 @@ runs:
2828
- uses: crazy-max/ghaction-github-runtime@3cb05d89e1f492524af3d41a1c98c83bc3025124
2929
- uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130
3030
- uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435
31+
with:
32+
driver-opts: network=host
3133
- env:
3234
DOCKER_REGISTRY: ${{ inputs.docker-registry }}
3335
DOCKER_TARGET: ${{ inputs.docker-target }}
3436
DOCKER_PUSH: ${{ inputs.docker-push }}
3537
TAG: ${{ inputs.tag }}
38+
RUNTIME_IMAGE: localhost:5000/linkerd/proxy-runtime:${{ inputs.tag }}
39+
PUSH_RUNTIME_IMAGE: true
3640
shell: bash
3741
run: bin/docker-build-${{ inputs.component }}
3842

.github/workflows/integration.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ jobs:
8080
needs: meta
8181
if: needs.meta.outputs.changed == 'true'
8282
runs-on: ${{ vars.LINKERD2_RUNNER || 'ubuntu-24.04' }}
83+
services:
84+
registry:
85+
image: registry:3
86+
ports:
87+
- 5000:5000
8388
strategy:
8489
matrix:
8590
component:

.github/workflows/release.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ jobs:
3737
contents: read
3838
packages: write # for docker/login-action
3939
id-token: write # for cosign
40+
services:
41+
registry:
42+
image: registry:3
43+
ports:
44+
- 5000:5000
4045
strategy:
4146
matrix:
4247
component:

Dockerfile-proxy renamed to Dockerfile.proxy

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
ARG RUNTIME_IMAGE=gcr.io/distroless/cc-debian12
21
ARG BUILDPLATFORM=linux/amd64
2+
ARG RUNTIME_IMAGE="cr.l5d.io/linkerd/proxy-runtime:latest"
3+
ARG TARGETARCH
34

45
# Precompile key slow-to-build dependencies
56
FROM --platform=$BUILDPLATFORM golang:1.25-alpine AS go-deps
@@ -43,8 +44,33 @@ RUN CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH go build -mod=readonly ./pkg/...
4344
COPY proxy-identity proxy-identity
4445
RUN CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH go build -o /out/proxy-identity -mod=readonly -ldflags "-s -w" ./proxy-identity
4546

46-
FROM $RUNTIME_IMAGE AS runtime
47+
## build proxy-init
48+
FROM --platform=$BUILDPLATFORM ghcr.io/linkerd/dev:v48-go AS proxy-init
49+
WORKDIR /build
50+
ARG PROXY_INIT_REPO="linkerd/linkerd2-proxy-init"
51+
ARG PROXY_INIT_REF="proxy-init/v2.4.3"
52+
RUN --mount=type=secret,id=github \
53+
export GITHUB_TOKEN_FILE=/run/secrets/github; \
54+
git init --initial-branch=main . && \
55+
git remote add origin https://github.com/${PROXY_INIT_REPO}.git && \
56+
git fetch --depth 1 origin ${PROXY_INIT_REF} && \
57+
git checkout --detach FETCH_HEAD
58+
RUN go mod download
59+
ARG TARGETARCH
60+
RUN CGO_ENABLED=0 GOOS=linux GOARCH=$TARGETARCH GO111MODULE=on \
61+
go build -o /out/linkerd2-proxy-init -mod=readonly -ldflags "-s -w" -v ./proxy-init
62+
63+
FROM $RUNTIME_IMAGE-$TARGETARCH AS runtime
4764
LABEL org.opencontainers.image.source=https://github.com/linkerd/linkerd2
65+
66+
COPY --from=proxy-init /out/linkerd2-proxy-init /usr/lib/linkerd/linkerd2-proxy-init
67+
# Set sys caps for iptables utilities and proxy-init
68+
USER root
69+
RUN ["/usr/sbin/setcap", "cap_net_raw,cap_net_admin+eip", "/usr/sbin/xtables-legacy-multi"]
70+
RUN ["/usr/sbin/setcap", "cap_net_raw,cap_net_admin+eip", "/usr/sbin/xtables-nft-multi"]
71+
RUN ["/usr/sbin/setcap", "cap_net_raw,cap_net_admin+eip", "/usr/lib/linkerd/linkerd2-proxy-init"]
72+
USER 65534
73+
4874
COPY --from=fetch /build/target/proxy/LICENSE /usr/lib/linkerd/LICENSE
4975
COPY --from=fetch /build/proxy-version /usr/lib/linkerd/linkerd2-proxy-version.txt
5076
COPY --from=fetch /build/linkerd2-proxy /usr/lib/linkerd/linkerd2-proxy

bin/docker-build-proxy

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
set -eu
44

5+
apko_version=v0.30.13
6+
57
if [ $# -ne 0 ]; then
68
echo "no arguments allowed for ${0##*/}, given: $*" >&2
79
exit 64
@@ -14,8 +16,11 @@ rootdir=$( cd "$bindir"/.. && pwd )
1416
. "$bindir"/_docker.sh
1517
# shellcheck source=_tag.sh
1618
. "$bindir"/_tag.sh
19+
# shellcheck source=_os.sh
20+
. "$bindir"/_os.sh
1721

18-
dockerfile=$rootdir/Dockerfile-proxy
22+
dockerfile=$rootdir/Dockerfile.proxy
23+
runtime_image="${RUNTIME_IMAGE:-"cr.l5d.io/linkerd/proxy-runtime:${TAG:-$(head_root_tag)}"}"
1924

2025
get_extra_options() {
2126
options=
@@ -25,9 +30,22 @@ get_extra_options() {
2530
echo "$options"
2631
}
2732

33+
# Build proxy base image with apko
34+
go install chainguard.dev/apko@$apko_version
35+
export PATH=$PATH:$(go env GOPATH)/bin
36+
# Add --local flag unless PUSH_RUNTIME_IMAGE is set
37+
apko build "$rootdir/proxy-runtime.yml" "$runtime_image" "$rootdir/proxy-runtime.tar"
38+
docker load < "$rootdir/proxy-runtime.tar"
39+
if [[ -n "${PUSH_RUNTIME_IMAGE:-}" ]]; then
40+
for arch in "arm64" "amd64"; do
41+
docker push "$runtime_image-$arch"
42+
done
43+
fi
44+
2845
# We want wordsplit for the extra options here:
2946
# shellcheck disable=SC2046
3047
docker_build proxy "${TAG:-$(head_root_tag)}" "$dockerfile" \
48+
--build-arg RUNTIME_IMAGE="$runtime_image" \
3149
--build-arg LINKERD_VERSION="${TAG:-$(head_root_tag)}" \
3250
--build-arg LINKERD2_PROXY_REPO="${LINKERD2_PROXY_REPO:-linkerd/linkerd2-proxy}" \
3351
--build-arg LINKERD2_PROXY_VERSION="${LINKERD2_PROXY_VERSION:-$(cat .proxy-version)}" \

charts/linkerd-control-plane/values.yaml

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -349,14 +349,6 @@ proxyInit:
349349
# -- Log format (`plain` or `json`) for the proxy-init
350350
# @default -- plain
351351
logFormat: ""
352-
image:
353-
# -- Docker image for the proxy-init container
354-
name: cr.l5d.io/linkerd/proxy-init
355-
# -- Pull policy for the proxy-init container image
356-
# @default -- imagePullPolicy
357-
pullPolicy: ""
358-
# -- Tag for the proxy-init container image
359-
version: v2.4.3
360352
# -- Changes the default value for the nf_conntrack_tcp_timeout_close_wait
361353
# kernel parameter. If used, runAsRoot needs to be true.
362354
closeWaitTimeoutSecs: 0

charts/partials/templates/_proxy-init.tpl

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,9 @@ args:
4646
- --subnets-to-ignore
4747
- {{ .Values.proxyInit.skipSubnets | quote }}
4848
{{- end }}
49-
image: {{.Values.proxyInit.image.name}}:{{.Values.proxyInit.image.version}}
50-
imagePullPolicy: {{.Values.proxyInit.image.pullPolicy | default .Values.imagePullPolicy}}
49+
image: {{.Values.proxy.image.name}}:{{.Values.proxy.image.version | default .Values.linkerdVersion}}
50+
command: ["/usr/lib/linkerd/linkerd2-proxy-init"]
51+
imagePullPolicy: {{.Values.proxy.image.pullPolicy | default .Values.imagePullPolicy}}
5152
name: linkerd-init
5253
{{ include "partials.resources" .Values.proxy.resources }}
5354
securityContext:

cli/cmd/doc.go

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -128,14 +128,6 @@ func generateAnnotationsDocs() []annotationDoc {
128128
Name: k8s.ProxyImagePullPolicyAnnotation,
129129
Description: "Docker image pull policy",
130130
},
131-
{
132-
Name: k8s.ProxyInitImageAnnotation,
133-
Description: "Linkerd init container image name",
134-
},
135-
{
136-
Name: k8s.ProxyInitImageVersionAnnotation,
137-
Description: "Linkerd init container image version",
138-
},
139131
{
140132
Name: k8s.DebugImageAnnotation,
141133
Description: "Linkerd debug container image name",

cli/cmd/inject.go

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -417,17 +417,10 @@ func getOverrideAnnotations(values *linkerd2.Values, base *linkerd2.Values) map[
417417
if proxy.Image.Name != baseProxy.Image.Name {
418418
overrideAnnotations[k8s.ProxyImageAnnotation] = proxy.Image.Name
419419
}
420-
if values.ProxyInit.Image.Name != base.ProxyInit.Image.Name {
421-
overrideAnnotations[k8s.ProxyInitImageAnnotation] = values.ProxyInit.Image.Name
422-
}
423420
if values.DebugContainer.Image.Name != base.DebugContainer.Image.Name {
424421
overrideAnnotations[k8s.DebugImageAnnotation] = values.DebugContainer.Image.Name
425422
}
426423

427-
if values.ProxyInit.Image.Version != base.ProxyInit.Image.Version {
428-
overrideAnnotations[k8s.ProxyInitImageVersionAnnotation] = values.ProxyInit.Image.Version
429-
}
430-
431424
if values.DebugContainer.Image.Version != base.DebugContainer.Image.Version {
432425
overrideAnnotations[k8s.DebugImageVersionAnnotation] = values.DebugContainer.Image.Version
433426
}

cli/cmd/inject_test.go

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -782,30 +782,6 @@ func TestProxyImageAnnotations(t *testing.T) {
782782
diffOverrides(t, expectedOverrides, overrides)
783783
}
784784

785-
func TestProxyInitImageAnnotations(t *testing.T) {
786-
baseValues, err := linkerd2.NewValues()
787-
if err != nil {
788-
t.Fatal(err)
789-
}
790-
values, err := baseValues.DeepCopy()
791-
if err != nil {
792-
t.Fatal(err)
793-
}
794-
values.ProxyInit.Image = &linkerd2.Image{
795-
Name: "my.registry/linkerd/proxy-init",
796-
Version: "test-proxy-init-version",
797-
}
798-
799-
expectedOverrides := map[string]string{
800-
k8s.ProxyInitImageAnnotation: "my.registry/linkerd/proxy-init",
801-
k8s.ProxyInitImageVersionAnnotation: "test-proxy-init-version",
802-
}
803-
804-
overrides := getOverrideAnnotations(values, baseValues)
805-
806-
diffOverrides(t, expectedOverrides, overrides)
807-
}
808-
809785
func TestNoAnnotations(t *testing.T) {
810786
baseValues, err := linkerd2.NewValues()
811787
if err != nil {

0 commit comments

Comments
 (0)