I improved the security and efficiency of PipeCD's codegen Docker image, which is critical infrastructure for the development workflow. This contribution fixed CVE vulnerabilities, reduced image size by 37%, and maintained full compatibility with all existing tooling.
What is PipeCD?
PipeCD is a CNCF Sandbox GitOps continuous deployment tool that automates application deployments to Kubernetes, ECS, Lambda, and other platforms. The codegen image is a critical development tool used to generate Go code from protobuf definitions.
The Problem
The existing codegen image had several issues:
- Security Vulnerabilities: Snyk flagged multiple CVEs related to curl and other dependencies in the
golang:1.25.2base image - Large Image Size: The image was ~800MB, containing many unnecessary dependencies
- Previous Failed Attempts: PR #6402 attempted to use
debian:bookworm-slimbut was reverted in #6404 because:- Missing
google/protobuf/*.protofiles (protoc needs these standard definitions) - mockgen needs the
gocommand at runtime
- Missing
My Solution
I implemented a multi-stage Docker build that addresses all issues:
Security & Size
- Base Image: Switched from
golang:1.25.2todebian:bookworm-slim - Size Reduction: Reduced from ~800MB to ~500MB (37% smaller)
- CVE Fixes: Eliminated curl-related vulnerabilities and other unnecessary dependencies
Functionality Preservation
- Proto Files: Installed
libprotobuf-devpackage to include standard proto files (google/protobuf/*.proto) - Go Runtime: Copied Go from
golang:1.25.2image since mockgen requires thegocommand - Architecture Support: Maintained both x86_64 and aarch64 support for protoc-gen-js
- All Tools: Ensured protoc, mockgen, protoc-gen-go, protoc-gen-grpc, and all plugins work correctly
Comprehensive Testing
I provided extensive testing evidence in the PR:
Build & Size Validation
docker build -t pipecd-codegen:test .
docker images pipecd-codegen:test --format "{{.Size}}"- ✅ Image builds successfully
- ✅ Size reduced to ~500MB (vs ~800MB before)
Binary Verification
protoc --version
go version
mockgen --version
ls /usr/local/bin/protoc-gen-*- ✅ All binaries present and functional
Proto Files Check
ls /usr/include/google/protobuf/*.proto
ls /go/src/github.com/envoyproxy/protoc-gen-validate/validate/*.proto- ✅ Standard proto files available
- ✅ Validation proto files included
Compilation Test
protoc -I . \
-I /go/src/github.com/envoyproxy/protoc-gen-validate \
--go_out=. --go_opt=paths=source_relative \
--go-grpc_out=. --go-grpc_opt=paths=source_relative \
--validate_out='lang=go:.' --validate_opt=paths=source_relative \
pkg/model/common.proto- ✅ Protoc compilation works with all plugins
Full Integration Test
docker run --rm -v $(pwd):/repo pipecd-codegen:test ./tool/codegen/codegen.sh /repo- ✅ Complete codegen script executes successfully
Technical Implementation
The key to solving this where others failed was:
- Multi-stage Build: Use
golang:1.25.2as builder, copy Go runtime to slim image - System Dependencies: Install
libprotobuf-devfor standard proto definitions - Comprehensive PATH: Set up proper Go environment variables and paths
- Architecture Handling: Properly handle both x86_64 and aarch64 protoc-gen-js binaries
Impact
- Security: Eliminated CVE vulnerabilities from base image
- Efficiency: 37% size reduction speeds up image pulls and reduces storage costs
- Developer Experience: All tools work seamlessly, no workflow disruption
- Reliability: Resolved issues that caused previous PR to be reverted
Review Process
The maintainers appreciated the thoroughness:
- Extensive testing documentation with screenshots
- Clear before/after comparisons
- Explanation of why previous attempts failed
- No breaking changes to developer workflow
Merged by khanhtc1202 after thorough validation.
Links: Pull Request #6461 • Issue #6429 • Repository