자체 빌드 이미지 3종(cloudnative-pg/cnpg-postgresql/etcd) + 대응 헬름 차트 도입
security-catalog 프로젝트에서 첫 실사용 자체 빌드 이미지 3종을 포팅한다 — 전부
상위 태그·베이스 OS 교체로 해소 안 되는 CVE(Go 모듈 정적 링크 또는 미수정 CRITICAL/
HIGH)를 자체 빌드(소스 컴파일 또는 SUSE BCI 재설치)로 대응한다:
- images/cloudnative-pg: CNPG operator, release-1.30 소스 컴파일 + bci-micro
- images/cnpg-postgresql: PostgreSQL 18.4, bci-base + zypper 재설치
- images/etcd: etcd v3.7.1, 소스 컴파일(x/text 강제 업그레이드) + bci-micro
함께 추가:
- manifests/helm/{cloudnative-pg,cnpg-cluster,etcd} — 위 이미지를 참조하는 카탈로그 차트
- scripts/deploy-test/*.sh, .claude/deploy-test-procedure.md — CVE 0건과 별개로
"실제로 뜨는가"를 검증하는 배포 스모크 테스트
- .claude/pitfalls.md — 자체 빌드/배포 테스트 중 실측한 함정 모음
검토 중 발견해 반영한 수정:
- cloudnative-pg 차트의 image 블록을 etcd와 동일한 registry/repository/tag 3필드+
따옴표 포맷으로 통일 — 기존 포맷(repository에 registry+repo 결합, 따옴표 없음)은
patch-catalog-tag.py 의 split 패처가 tag만 갱신하고 repository는 그대로 남기는
조용한 부분 치환을 일으켜, 향후 레지스트리 마이그레이션 시 깨진 참조를 만들 수 있었다
- cnpg-cluster 차트의 SLES 커버리지 코멘트를 최신 실측(trivy가 SLES 15.7을 정상
커버함, 2026-07-29 재측정)에 맞게 정정 — 폐기된 "측정 불가/OVAL 우회 필요" 결론이
남아있었다
- CLAUDE.md/MEMORY.md 의 "images/ 디렉토리 없음" 서술을 갱신하고, 레지스트리
마이그레이션(docker.io/wbsong111 → docker.io/paasup)·decisions/analysis 문서 이관·
리소스 프로파일 추가를 다음 작업으로 기록
이 3개 이미지는 아직 dip-catalog 자체 CI(build-image.yml)로 빌드·게이트·push 를
실행해본 적이 없다 — 현재 참조 태그는 security-catalog 쪽에서 이미 검증된 것이다.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
# Etcd
|
||||
|
||||
  
|
||||
|
||||
## Changelog
|
||||
|
||||
see [RELEASENOTES.md](RELEASENOTES.md)
|
||||
|
||||
A Helm chart for a Etcd HA-cluster on Kubernetes
|
||||
|
||||
## TL;DR
|
||||
|
||||
```bash
|
||||
helm repo add groundhog2k https://groundhog2k.github.io/helm-charts/
|
||||
helm install my-release groundhog2k/etcd
|
||||
```
|
||||
|
||||
## Introduction
|
||||
|
||||
This chart uses the original [Etcd image from Quay.io](https://quay.io/repository/coreos/etcd) to deploy a stateful Etcd cluster in Kubernetes.
|
||||
|
||||
It fully supports deployment of the multi-architecture docker image.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Kubernetes 1.12+
|
||||
- Helm 3.x
|
||||
- PV provisioner support in the underlying infrastructure
|
||||
|
||||
## Installing the Chart
|
||||
|
||||
To install the chart with the release name `my-release`:
|
||||
|
||||
```bash
|
||||
helm install my-release groundhog2k/etcd
|
||||
```
|
||||
|
||||
## Uninstalling the Chart
|
||||
|
||||
To uninstall/delete the `my-release` deployment:
|
||||
|
||||
```bash
|
||||
helm uninstall my-release
|
||||
```
|
||||
|
||||
## Common parameters
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| fullnameOverride | string | `""` | Fully override the deployment name |
|
||||
| nameOverride | string | `""` | Partially override the deployment name |
|
||||
|
||||
## Deployment parameters
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| image.pullPolicy | string | `"IfNotPresent"` | Image pull policy |
|
||||
| image.registry | string | `"quay.io/coreos"` | Image registry |
|
||||
| image.repository | string | `"etcd"` | Image name |
|
||||
| image.tag | string | `""` | Image tag |
|
||||
| initImage.pullPolicy | string | `"IfNotPresent"` | Init image pull policy |
|
||||
| initImage.registry | string | `"docker.io"` | Image registry |
|
||||
| initImage.repository | string | `"busybox"` | Init image name |
|
||||
| initImage.tag | string | `"stable"` | Init image tag |
|
||||
| imagePullSecrets | list | `[]` | Image pull secrets |
|
||||
| extraInitContainers | list | `[]` | Extra init containers |
|
||||
| extaContainers | list | `[]` | Extra containers for usage as sidecars |
|
||||
| startupProbe | object | `see values.yaml` | Startup probe configuration |
|
||||
| livenessProbe | object | `see values.yaml` | Liveness probe configuration |
|
||||
| readinessProbe | object | `see values.yaml` | Readiness probe configuration |
|
||||
| customStartupProbe | object | `{}` | Custom startup probe (overwrites default startup probe configuration) |
|
||||
| customLivenessProbe | object | `{}` | Custom liveness probe (overwrites default liveness probe configuration) |
|
||||
| customReadinessProbe | object | `{}` | Custom readiness probe (overwrites default readiness probe configuration) |
|
||||
| resources | object | `{}` | Resource limits and requests |
|
||||
| priorityClassName | string | `""` | Deployment priority class name |
|
||||
| nodeSelector | object | `{}` | Deployment node selector |
|
||||
| customLabels | object | `{}` | Additional labels for Deployment or StatefulSet |
|
||||
| customAnnotations | object | `{}` | Additional annotations for Deployment or StatefulSet |
|
||||
| podAnnotations | object | `{}` | Additional pod annotations |
|
||||
| podLabels | object | `{}` | Additional pod labels |
|
||||
| podSecurityContext | object | `see values.yaml` | Pod security context |
|
||||
| securityContext | object | `see values.yaml` | Container security context |
|
||||
| env | list | `[]` | Additional container environmment variables |
|
||||
| args | list | `[]` | Additional container command arguments |
|
||||
| rbac.create | bool | `true` | Enable creation of RBAC |
|
||||
| serviceAccount.annotations | object | `{}` | Additional service account annotations |
|
||||
| serviceAccount.create | bool | `true` | Enable service account creation |
|
||||
| serviceAccount.name | string | `""` | Optional name of the service account |
|
||||
| serviceAccount.automountServiceAccountToken | bool | `true` | Specifies whether a service account token should be automatically mounted |
|
||||
| affinity | object | `{}` | Affinity for pod assignment |
|
||||
| tolerations | list | `[]` | Tolerations for pod assignment |
|
||||
| topologySpreadConstraints | object | `{}` | Topology spread constraints for pods |
|
||||
| podManagementPolicy | string | `"Parallel"` | Pod management policy |
|
||||
| updateStrategyType | string | `"RollingUpdate"` | Pod update strategy |
|
||||
| replicas | int | `1` | Number of replicas (Due to the nature of etcd cluster initialization this value must be set before deploying the cluster) |
|
||||
| revisionHistoryLimit | int | `nil` | Maximum number of revisions maintained in revision history |
|
||||
| podDisruptionBudget | object | `{}` | Pod disruption budget |
|
||||
| podDisruptionBudget.minAvailable | int | `nil` | Minimum number of pods that must be available after eviction |
|
||||
| podDisruptionBudget.maxUnavailable | int | `nil` | Maximum number of pods that can be unavailable after eviction |
|
||||
| clusterDomain | string | `"cluster.local"` | Kubernetes cluster domain (DNS) suffix |
|
||||
|
||||
## Service parameters
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| service.type | string | `"ClusterIP"` | Service type |
|
||||
| service.clusterIP | string | `nil` | The cluster ip address (only relevant for type LoadBalancer or NodePort) |
|
||||
| service.loadBalancerIP | string | `nil` | The load balancer ip address (only relevant for type LoadBalancer) |
|
||||
| service.loadBalancerSourceRanges | list | `[]` | The list of IP CIDR ranges that are allowed to access the load balancer (only relevent for type LoadBalancer) |
|
||||
| service.client.port | int | `2379` | Client service port |
|
||||
| service.client.nodePort | int | `nil` | Service node port (only relevant for type LoadBalancer or NodePort) |
|
||||
| service.peer.port | int | `2380` | Peer service port |
|
||||
| service.peer.nodePort | int | `nil` | Service node port (only relevant for type LoadBalancer or NodePort) |
|
||||
| service.annotations | object | `{}` | Additional service annotations |
|
||||
| service.labels | object | `{}` | Additional service labels |
|
||||
|
||||
## Service monitor parameters
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| serviceMonitor.enabled | bool | `false` | Enable service monitor |
|
||||
| serviceMonitor.additionalLabels | object | `{}` | Additional labels for the service monitor object |
|
||||
| serviceMonitor.annotations | object | `{}` | Annotations for the service monitor object |
|
||||
| serviceMonitor.interval | Duration | `nil` | Scrape interval for prometheus |
|
||||
| serviceMonitor.scrapeTimeout | Duration | `nil` | Scrape timeout value |
|
||||
| serviceMonitor.extraEndpointParameters | object | `nil` | Extra parameters rendered to the [service monitor endpoint](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#endpoint) |
|
||||
| serviceMonitor.extraParameters | object | `nil` | Extra parameters rendered to the [service monitor object](https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#servicemonitorspec) |
|
||||
|
||||
## Network policies
|
||||
|
||||
Allows to define optional network policies for [ingress and egress](https://kubernetes.io/docs/concepts/services-networking/network-policies/)
|
||||
The policyTypes will be automatically set
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| networkPolicy.ingress | object | `{}` | Ingress network policies |
|
||||
| networkPolicy.egress | object | `{}` | Egress network policies |
|
||||
|
||||
## Storage parameters
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| storage.accessModes[0] | string | `"ReadWriteOnce"` | Storage access mode |
|
||||
| storage.volumeName | string | `"etcd-data"` | Internal volume name and prefix of a created PVC |
|
||||
| storage.persistentVolumeClaimName | string | `nil` | PVC name when existing storage volume should be used |
|
||||
| storage.requestedSize | string | `nil` | Size for new PVC, when no existing PVC is used |
|
||||
| storage.className | string | `nil` | Storage class name |
|
||||
| storage.annotations | object | `{}` | Additional storage annotations |
|
||||
| storage.labels | object | `{}` | Additional storage labels |
|
||||
| extraStorage | list | `[]` | A list of additional existing PVC that will be mounted into the container |
|
||||
| extraStorage[].name | string | `nil` | Internal name of the volume |
|
||||
| extraStorage[].pvcName | string | `nil` | Name of the existing PVC |
|
||||
| extraStorage[].mountPath | string | `nil` | Mount path where the PVC should be mounted into the container |
|
||||
|
||||
## Etcd settings
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| settings.clusterToken | bool | `"etcd-cluster-0"` | Unique cluser token |
|
||||
| settings.https.enabled | bool | `false` | Enable HTTPS |
|
||||
| settings.https.autoTls | bool | `false` | Automatic TLS mode of etcd (TLS certs. created automaically) |
|
||||
| settings.shutdownDelay | int | `3` | Delay after termination request to give etcd process time for graceful shutdown |
|
||||
|
||||
## Etcd secrets and configuration
|
||||
|
||||
| Key | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| extraSecrets | list | `[]` | A list of additional existing secrets that will be mounted into the container |
|
||||
| extraSecrets[].name | string | `nil` | Name of the existing K8s secret |
|
||||
| extraSecrets[].defaultMode | int | `0440` | Mount default access mode |
|
||||
| extraSecrets[].mountPath | string | `nil` | Mount path where the secret should be mounted into the container (f.e. /mysecretfolder) |
|
||||
| extraConfigs | list | `[]` | A list of additional existing configMaps that will be mounted into the container |
|
||||
| extraConfigs[].name | string | `nil` | Name of the existing K8s configMap |
|
||||
| extraConfigs[].defaultMode | int | `0440` | Mount default access mode |
|
||||
| extraConfigs[].mountPath | string | `nil` | Mount path where the configMap should be mounted into the container (f.e. /myconfigfolder) |
|
||||
| extraEnvSecrets | list | `[]` | A list of existing secrets that will be mounted into the container as environment variables |
|
||||
Reference in New Issue
Block a user