stefanprodan / kustomizer

An experimental package manager for distributing Kubernetes configuration as OCI artifacts.
https://kustomizer.dev
Apache License 2.0
286 stars 13 forks source link

Build inventory should match the original manifest no matter the flag #84

Open FrenchBen opened 1 year ago

FrenchBen commented 1 year ago

Description

Kustomizer allows you to take an artifact and a kustomize local repo to build a manifest. These can have duplicate manifests when specifying both the remote OCI artifact and the local storage.

Steps to reproduce

Create the manifests using the various flags

$ kustomizer build inventory demo-app --kustomize ./examples/demo-app --artifact oci://ghcr.io/stefanprodan/kustomizer-demo-app:1.0.0 > artifact-kustomize.yaml
$ kustomizer build inventory demo-app --kustomize ./examples/demo-app > kustomize.yaml
$ kustomizer build inventory demo-app  --artifact oci://ghcr.io/stefanprodan/kustomizer-demo-app:1.0.0 > artifact.yaml

Now diff the manifests

$ diff artifact.yaml kustomize.yaml
$
$ diff artifact-kustomize.yaml kustomize.yaml
11,19d10
< kind: Namespace
< metadata:
<   annotations:
<     env: demo
<   labels:
<     app.kubernetes.io/instance: webapp
<   name: kustomizer-demo-app
< ---
< apiVersion: v1
36,51d26
< data:
<   redis.conf: |
<     maxmemory 64mb
<     maxmemory-policy allkeys-lru
<     save ""
<     appendonly no
< kind: ConfigMap
< metadata:
<   annotations:
<     env: demo
<   labels:
<     app.kubernetes.io/instance: webapp
<   name: redis-config-bd2fcfgt6k
<   namespace: kustomizer-demo-app
< ---
< apiVersion: v1
81,103d55
<   name: backend
<   namespace: kustomizer-demo-app
< spec:
<   ports:
<   - name: http
<     port: 9898
<     protocol: TCP
<     targetPort: http
<   - name: grpc
<     port: 9999
<     protocol: TCP
<     targetPort: grpc
<   selector:
<     app: backend
<   type: ClusterIP
< ---
< apiVersion: v1
< kind: Service
< metadata:
<   annotations:
<     env: demo
<   labels:
<     app.kubernetes.io/instance: webapp
123,141d74
<   name: cache
<   namespace: kustomizer-demo-app
< spec:
<   ports:
<   - name: redis
<     port: 6379
<     protocol: TCP
<     targetPort: redis
<   selector:
<     app: cache
<   type: ClusterIP
< ---
< apiVersion: v1
< kind: Service
< metadata:
<   annotations:
<     env: demo
<   labels:
<     app.kubernetes.io/instance: webapp
154,172d86
< apiVersion: v1
< kind: Service
< metadata:
<   annotations:
<     env: demo
<   labels:
<     app.kubernetes.io/instance: webapp
<   name: frontend
<   namespace: kustomizer-demo-app
< spec:
<   ports:
<   - name: http
<     port: 80
<     protocol: TCP
<     targetPort: http
<   selector:
<     app: frontend
<   type: ClusterIP
< ---
259,337d172
<   name: backend
<   namespace: kustomizer-demo-app
< spec:
<   minReadySeconds: 3
<   progressDeadlineSeconds: 60
<   revisionHistoryLimit: 5
<   selector:
<     matchLabels:
<       app: backend
<   strategy:
<     rollingUpdate:
<       maxUnavailable: 0
<     type: RollingUpdate
<   template:
<     metadata:
<       annotations:
<         prometheus.io/port: "9797"
<         prometheus.io/scrape: "true"
<       labels:
<         app: backend
<     spec:
<       containers:
<       - command:
<         - ./podinfo
<         - --port=9898
<         - --port-metrics=9797
<         - --grpc-port=9999
<         - --grpc-service-name=backend
<         - --level=info
<         - --cache-server=cache:6379
<         env:
<         - name: PODINFO_UI_COLOR
<           value: '#34577c'
<         image: ghcr.io/stefanprodan/podinfo:6.0.0
<         imagePullPolicy: IfNotPresent
<         livenessProbe:
<           exec:
<             command:
<             - podcli
<             - check
<             - http
<             - localhost:9898/healthz
<           initialDelaySeconds: 5
<           timeoutSeconds: 5
<         name: backend
<         ports:
<         - containerPort: 9898
<           name: http
<           protocol: TCP
<         - containerPort: 9797
<           name: http-metrics
<           protocol: TCP
<         - containerPort: 9999
<           name: grpc
<           protocol: TCP
<         readinessProbe:
<           exec:
<             command:
<             - podcli
<             - check
<             - http
<             - localhost:9898/readyz
<           initialDelaySeconds: 5
<           timeoutSeconds: 5
<         resources:
<           limits:
<             cpu: 2000m
<             memory: 512Mi
<           requests:
<             cpu: 100m
<             memory: 32Mi
< ---
< apiVersion: apps/v1
< kind: Deployment
< metadata:
<   annotations:
<     env: demo
<   labels:
<     app.kubernetes.io/instance: webapp
401,463d235
<   name: cache
<   namespace: kustomizer-demo-app
< spec:
<   selector:
<     matchLabels:
<       app: cache
<   template:
<     metadata:
<       labels:
<         app: cache
<     spec:
<       containers:
<       - command:
<         - redis-server
<         - /redis-master/redis.conf
<         image: public.ecr.aws/docker/library/redis:6.2.0
<         imagePullPolicy: IfNotPresent
<         livenessProbe:
<           initialDelaySeconds: 5
<           tcpSocket:
<             port: redis
<           timeoutSeconds: 5
<         name: redis
<         ports:
<         - containerPort: 6379
<           name: redis
<           protocol: TCP
<         readinessProbe:
<           exec:
<             command:
<             - redis-cli
<             - ping
<           initialDelaySeconds: 5
<           timeoutSeconds: 5
<         resources:
<           limits:
<             cpu: 1000m
<             memory: 128Mi
<           requests:
<             cpu: 100m
<             memory: 32Mi
<         volumeMounts:
<         - mountPath: /var/lib/redis
<           name: data
<         - mountPath: /redis-master
<           name: config
<       volumes:
<       - emptyDir: {}
<         name: data
<       - configMap:
<           items:
<           - key: redis.conf
<             path: redis.conf
<           name: redis-config-bd2fcfgt6k
<         name: config
< ---
< apiVersion: apps/v1
< kind: Deployment
< metadata:
<   annotations:
<     env: demo
<   labels:
<     app.kubernetes.io/instance: webapp
535,612d306
< apiVersion: apps/v1
< kind: Deployment
< metadata:
<   annotations:
<     env: demo
<   labels:
<     app.kubernetes.io/instance: webapp
<   name: frontend
<   namespace: kustomizer-demo-app
< spec:
<   minReadySeconds: 3
<   progressDeadlineSeconds: 60
<   revisionHistoryLimit: 5
<   selector:
<     matchLabels:
<       app: frontend
<   strategy:
<     rollingUpdate:
<       maxUnavailable: 0
<     type: RollingUpdate
<   template:
<     metadata:
<       annotations:
<         prometheus.io/port: "9797"
<         prometheus.io/scrape: "true"
<       labels:
<         app: frontend
<     spec:
<       containers:
<       - command:
<         - ./podinfo
<         - --port=9898
<         - --port-metrics=9797
<         - --level=info
<         - --backend-url=http://backend:9898/echo
<         - --cache-server=cache:6379
<         env:
<         - name: PODINFO_UI_COLOR
<           value: '#34577c'
<         image: ghcr.io/stefanprodan/podinfo:6.0.0
<         imagePullPolicy: IfNotPresent
<         livenessProbe:
<           exec:
<             command:
<             - podcli
<             - check
<             - http
<             - localhost:9898/healthz
<           initialDelaySeconds: 5
<           timeoutSeconds: 5
<         name: frontend
<         ports:
<         - containerPort: 9898
<           name: http
<           protocol: TCP
<         - containerPort: 9797
<           name: http-metrics
<           protocol: TCP
<         - containerPort: 9999
<           name: grpc
<           protocol: TCP
<         readinessProbe:
<           exec:
<             command:
<             - podcli
<             - check
<             - http
<             - localhost:9898/readyz
<           initialDelaySeconds: 5
<           timeoutSeconds: 5
<         resources:
<           limits:
<             cpu: 1000m
<             memory: 128Mi
<           requests:
<             cpu: 100m
<             memory: 32Mi
< ---
636,683d329
< ---
< apiVersion: autoscaling/v2beta2
< kind: HorizontalPodAutoscaler
< metadata:
<   annotations:
<     env: demo
<   labels:
<     app.kubernetes.io/instance: webapp
<   name: backend
<   namespace: kustomizer-demo-app
< spec:
<   maxReplicas: 2
<   metrics:
<   - resource:
<       name: cpu
<       target:
<         averageUtilization: 99
<         type: Utilization
<     type: Resource
<   minReplicas: 1
<   scaleTargetRef:
<     apiVersion: apps/v1
<     kind: Deployment
<     name: backend
< ---
< apiVersion: autoscaling/v2beta2
< kind: HorizontalPodAutoscaler
< metadata:
<   annotations:
<     env: demo
<   labels:
<     app.kubernetes.io/instance: webapp
<   name: frontend
<   namespace: kustomizer-demo-app
< spec:
<   maxReplicas: 4
<   metrics:
<   - resource:
<       name: cpu
<       target:
<         averageUtilization: 99
<         type: Utilization
<     type: Resource
<   minReplicas: 1
<   scaleTargetRef:
<     apiVersion: apps/v1
<     kind: Deployment
<     name: frontend

Using both --artifact and --kustomize will duplicate each resource.

If the flags cannot be combined, then it should either state it, or create a merged manifest.

stefanprodan commented 1 year ago

@FrenchBen thanks for the report, I think an error should be printed when both flags are set.

FrenchBen commented 1 year ago

@stefanprodan Similarly, I expected the output of build inventory and kustomize build to be the same, but the diff says otherwise: Using the uploaded artifact

$ diff <(kustomizer build inventory demo-app  --artifact oci://ghcr.io/stefanprodan/kustomizer-demo-app:1.0.0) <(kustomize build ./examples/demo-app)
354,355d353
< ---
<

Same output with a local overlay:

$ diff <(kustomizer build inventory demo-app  --kustomize ./examples/demo-app) <(kustomize build ./examples/demo-app)
354,355d353
< ---
<
stefanprodan commented 1 year ago

I expected the output of build inventory and kustomize build to be the same

No this is not the case, Kustomizer orders and labels objects differently

FrenchBen commented 1 year ago

In the above, they are ordered the same way, but Kustomizer will add a terminating --- to the manifest, which Kustomize doesn't