mirror of
https://github.com/stefanprodan/podinfo.git
synced 2026-08-23 22:26:29 +00:00
Merge pull request #192 from stefanprodan/cue-refac
Refactor CUE module
This commit is contained in:
@@ -92,7 +92,7 @@ swagger:
|
||||
|
||||
.PHONY: cue-mod
|
||||
cue-mod:
|
||||
@cd cue && cue get go k8s.io/api/... && cue get go github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1
|
||||
@cd cue && cue get go k8s.io/api/...
|
||||
|
||||
.PHONY: cue-gen
|
||||
cue-gen:
|
||||
|
||||
+40
-7
@@ -1,22 +1,55 @@
|
||||
# CUE Demo
|
||||
# Podinfo CUE module
|
||||
|
||||
This directory contains a [cuelang module](https://cuelang.org/docs/) and tooling to generate podinfo resources.
|
||||
This directory contains a [CUE](https://cuelang.org/docs/) module and tooling
|
||||
for generating podinfo's Kubernetes resources.
|
||||
|
||||
It defines a `podinfo.#Application` definition which takes a `podinfo.#Config` as input.
|
||||
The `podinfo.#Config` definition is modelled on the `podinfo` Helm chart `values.yaml` file.
|
||||
The module contains a `podinfo.#Application` definition which takes `podinfo.#Config` as input.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Generate the Kubernetes API definitions required by podinfo with:
|
||||
Install CUE with:
|
||||
|
||||
```shell
|
||||
brew install cue
|
||||
```
|
||||
|
||||
Generate the Kubernetes API definitions required by this module with:
|
||||
|
||||
```shell
|
||||
cue get go k8s.io/api/...
|
||||
cue get go github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Configure the application in `main.cue`.
|
||||
Configure the application in `main.cue`:
|
||||
|
||||
```cue
|
||||
app: podinfo.#Application & {
|
||||
config: {
|
||||
meta: {
|
||||
name: "podinfo"
|
||||
namespace: "default"
|
||||
}
|
||||
image: tag: "6.1.3"
|
||||
resources: requests: {
|
||||
cpu: "100m"
|
||||
memory: "16Mi"
|
||||
}
|
||||
hpa: {
|
||||
enabled: true
|
||||
maxReplicas: 3
|
||||
}
|
||||
ingress: {
|
||||
enabled: true
|
||||
className: "nginx"
|
||||
host: "podinfo.example.com"
|
||||
tls: true
|
||||
annotations: "cert-manager.io/cluster-issuer": "letsencrypt"
|
||||
}
|
||||
serviceMonitor: enabled: true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Generate the manifests
|
||||
|
||||
|
||||
+7
-10
@@ -3,24 +3,21 @@ module github.com/stefanprodan/podinfo/cue
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/cert-manager/cert-manager v1.8.0 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/logr v1.2.0 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/go-cmp v0.5.7 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/go-cmp v0.5.5 // indirect
|
||||
github.com/google/gofuzz v1.1.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
golang.org/x/net v0.0.0-20220412020605-290c469a71a5 // indirect
|
||||
golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
|
||||
golang.org/x/text v0.3.7 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
k8s.io/api v0.23.5 // indirect
|
||||
k8s.io/apiextensions-apiserver v0.23.4 // indirect
|
||||
k8s.io/apimachinery v0.23.5 // indirect
|
||||
k8s.io/klog/v2 v2.60.1 // indirect
|
||||
k8s.io/utils v0.0.0-20220210201930-3a6ce19ff2f9 // indirect
|
||||
sigs.k8s.io/gateway-api v0.4.1 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
|
||||
k8s.io/klog/v2 v2.30.0 // indirect
|
||||
k8s.io/utils v0.0.0-20211116205334-6203023598ed // indirect
|
||||
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
||||
)
|
||||
|
||||
-786
File diff suppressed because it is too large
Load Diff
+20
-14
@@ -4,24 +4,30 @@ import (
|
||||
podinfo "github.com/stefanprodan/podinfo/cue/podinfo"
|
||||
)
|
||||
|
||||
resources: (podinfo.#Application & {
|
||||
input: {
|
||||
app: podinfo.#Application & {
|
||||
config: {
|
||||
meta: {
|
||||
name: "podinfo"
|
||||
annotations: {
|
||||
"app.kubernetes.io/part-of": "podinfo"
|
||||
}
|
||||
name: "podinfo"
|
||||
namespace: "default"
|
||||
}
|
||||
image: {
|
||||
repository: "ghcr.io/stefanprodan/podinfo"
|
||||
tag: "6.1.3"
|
||||
image: tag: "6.1.3"
|
||||
resources: requests: {
|
||||
cpu: "100m"
|
||||
memory: "16Mi"
|
||||
}
|
||||
resources: requests: cpu: "100m"
|
||||
hpa: {
|
||||
enabled: true
|
||||
minReplicas: 2
|
||||
maxReplicas: 4
|
||||
cpu: 99
|
||||
maxReplicas: 3
|
||||
}
|
||||
ingress: {
|
||||
enabled: true
|
||||
className: "nginx"
|
||||
host: "podinfo.example.com"
|
||||
tls: true
|
||||
annotations: "cert-manager.io/cluster-issuer": "letsencrypt"
|
||||
}
|
||||
serviceMonitor: enabled: true
|
||||
}
|
||||
}).out
|
||||
}
|
||||
|
||||
objects: app.objects
|
||||
|
||||
+1
-1
@@ -7,6 +7,6 @@ import (
|
||||
|
||||
command: gen: {
|
||||
task: print: cli.Print & {
|
||||
text: yaml.MarshalStream([ for x in resources {x}])
|
||||
text: yaml.MarshalStream([ for x in objects {x}])
|
||||
}
|
||||
}
|
||||
|
||||
+18
-13
@@ -1,21 +1,26 @@
|
||||
package podinfo
|
||||
|
||||
#Application: {
|
||||
input: #Config
|
||||
out: {
|
||||
sa: #ServiceAccount & {_config: input}
|
||||
deploy: #Deployment & {
|
||||
_config: input
|
||||
_serviceAccount: sa.metadata.name
|
||||
config: #Config
|
||||
|
||||
objects: {
|
||||
service: #Service & {_config: config}
|
||||
account: #ServiceAccount & {_config: config}
|
||||
deployment: #Deployment & {
|
||||
_config: config
|
||||
_serviceAccount: account.metadata.name
|
||||
}
|
||||
service: #Service & {_config: input}}
|
||||
if input.hpa.enabled == true {
|
||||
out: hpa: #HorizontalPodAutoscaler & {_config: input}
|
||||
}
|
||||
if input.serviceMonitor.enabled == true {
|
||||
out: serviceMonitor: #ServiceMonitor & {_config: input}
|
||||
|
||||
if config.hpa.enabled == true {
|
||||
objects: hpa: #HorizontalPodAutoscaler & {_config: config}
|
||||
}
|
||||
if input.ingress.enabled == true {
|
||||
out: ingress: #Ingress & {_config: input}
|
||||
|
||||
if config.ingress.enabled == true {
|
||||
objects: ingress: #Ingress & {_config: config}
|
||||
}
|
||||
|
||||
if config.serviceMonitor.enabled == true {
|
||||
objects: serviceMonitor: #ServiceMonitor & {_config: config}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package podinfo
|
||||
|
||||
import (
|
||||
certmanv1 "github.com/cert-manager/cert-manager/pkg/apis/certmanager/v1"
|
||||
"encoding/yaml"
|
||||
)
|
||||
|
||||
#certConfig: {
|
||||
dnsNames: [string]
|
||||
tlsSecretName: string
|
||||
issuerRef: string
|
||||
}
|
||||
|
||||
#Certificate: certmanv1.#Certificate & {
|
||||
_config: #Config
|
||||
apiVersion: "v1"
|
||||
kind: "Certificate"
|
||||
metadata: _config.meta
|
||||
spec: certmanv1.#CertificateSpec & {
|
||||
dnsNames: _config.cert.dnsNames
|
||||
secretName: _config.cert.tlsSecretName
|
||||
issuerRef: yaml.Marshal(_config.cert.issuerRef)
|
||||
}
|
||||
}
|
||||
+22
-40
@@ -6,54 +6,36 @@ import (
|
||||
)
|
||||
|
||||
#Config: {
|
||||
meta: metav1.#ObjectMeta
|
||||
meta: metav1.#ObjectMeta
|
||||
hpa: #hpaConfig
|
||||
ingress: #ingressConfig
|
||||
service: #serviceConfig
|
||||
serviceMonitor: #serviceMonConfig
|
||||
|
||||
image: {
|
||||
repository: *"ghcr.io/stefanprodan/podinfo" | string
|
||||
tag: string
|
||||
pullPolicy: *"IfNotPresent" | string
|
||||
tag: string
|
||||
}
|
||||
selectorLabels: {
|
||||
"app.kubernetes.io/name": meta.name
|
||||
}
|
||||
replicas: *1 | int
|
||||
service: #serviceConfig
|
||||
host: string
|
||||
cache: string
|
||||
backends: [string]
|
||||
|
||||
cache?: string & =~"^tcp://"
|
||||
backends: [...string]
|
||||
logLevel: *"info" | string
|
||||
faults: {
|
||||
delay: *false | bool
|
||||
error: *false | bool
|
||||
unhealthy: *false | bool
|
||||
unready: *false | bool
|
||||
}
|
||||
h2c: {
|
||||
enabled: *false | bool
|
||||
}
|
||||
ui: {
|
||||
color: *"#34577c" | string
|
||||
message: *"" | string
|
||||
logo: *"" | string
|
||||
}
|
||||
podAnnotations: {[ string]: string}
|
||||
securityContext: corev1.#PodSecurityContext
|
||||
resources: *{
|
||||
replicas: *1 | int
|
||||
|
||||
resources: *{
|
||||
requests: {
|
||||
cpu: "1m"
|
||||
memory: "16Mi"
|
||||
}
|
||||
limits: memory: "128Mi"
|
||||
} | corev1.#ResourceRequirements
|
||||
nodeSelector: {[ string]: string}
|
||||
affinity: corev1.#Affinity
|
||||
tolerations: [ ...corev1.#Toleration]
|
||||
tls: {
|
||||
enabled: *false | bool
|
||||
port: *9899 | int
|
||||
certPath: *"/data/cert" | string
|
||||
secretName: *"" | string
|
||||
}
|
||||
cert: #certConfig
|
||||
hpa: #hpaConfig
|
||||
ingress: #ingressConfig
|
||||
serviceMonitor: #serviceMonConfig
|
||||
|
||||
selectorLabels: *{"app.kubernetes.io/name": meta.name} | {[ string]: string}
|
||||
meta: annotations: *{"app.kubernetes.io/version": "\(image.tag)"} | {[ string]: string}
|
||||
meta: labels: *selectorLabels | {[ string]: string}
|
||||
|
||||
securityContext?: corev1.#PodSecurityContext
|
||||
affinity?: corev1.#Affinity
|
||||
tolerations?: [ ...corev1.#Toleration]
|
||||
}
|
||||
|
||||
+28
-41
@@ -12,7 +12,7 @@ import (
|
||||
kind: "Deployment"
|
||||
metadata: _config.meta
|
||||
spec: appsv1.#DeploymentSpec & {
|
||||
if _config.hpa.enabled == false {
|
||||
if !_config.hpa.enabled {
|
||||
replicas: _config.replicas
|
||||
}
|
||||
strategy: {
|
||||
@@ -23,29 +23,33 @@ import (
|
||||
template: {
|
||||
metadata: {
|
||||
labels: _config.selectorLabels
|
||||
annotations: {
|
||||
"prometheus.io/scrape": "true"
|
||||
"prometheus.io/port": "\(_config.service.metricsPort)"
|
||||
_config.podAnnotations
|
||||
if !_config.serviceMonitor.enabled {
|
||||
annotations: {
|
||||
"prometheus.io/scrape": "true"
|
||||
"prometheus.io/port": "\(_config.service.metricsPort)"
|
||||
}
|
||||
}
|
||||
}
|
||||
spec: corev1.#PodSpec & {
|
||||
terminationGracePeriodSeconds: 30
|
||||
terminationGracePeriodSeconds: 15
|
||||
serviceAccountName: _serviceAccount
|
||||
containers: [
|
||||
{
|
||||
name: "podinfo"
|
||||
image: "\(_config.image.repository):\(_config.image.tag)"
|
||||
imagePullPolicy: _config.image.pullPolicy
|
||||
securityContext: _config.securityContext
|
||||
command: [
|
||||
"./podinfo",
|
||||
"--port=\(_config.service.httpPort)",
|
||||
"--port-metrics=\(_config.service.metricsPort)",
|
||||
"--grpc-port=\(_config.service.grpcPort)",
|
||||
"--level=\(_config.logLevel)",
|
||||
"--random-delay=\(_config.faults.delay)",
|
||||
"--random-error=\(_config.faults.error)",
|
||||
if _config.cache != _|_ {
|
||||
"--cache-server=\(_config.cache)"
|
||||
},
|
||||
for b in _config.backends {
|
||||
"--backend-url=\(b)"
|
||||
},
|
||||
]
|
||||
ports: [
|
||||
{
|
||||
@@ -65,57 +69,40 @@ import (
|
||||
},
|
||||
]
|
||||
livenessProbe: {
|
||||
exec: {
|
||||
command: [
|
||||
"podcli",
|
||||
"check",
|
||||
"http",
|
||||
"localhost:\(_config.service.httpPort)/healthz",
|
||||
]
|
||||
httpGet: {
|
||||
path: "/healthz"
|
||||
port: "http"
|
||||
}
|
||||
initialDelaySeconds: 1
|
||||
timeoutSeconds: 5
|
||||
}
|
||||
readinessProbe: {
|
||||
exec: {
|
||||
command: [
|
||||
"podcli",
|
||||
"check",
|
||||
"http",
|
||||
"localhost:\(_config.service.httpPort)/readyz",
|
||||
]
|
||||
httpGet: {
|
||||
path: "/readyz"
|
||||
port: "http"
|
||||
}
|
||||
initialDelaySeconds: 1
|
||||
timeoutSeconds: 5
|
||||
}
|
||||
volumeMounts: [
|
||||
{
|
||||
name: "data"
|
||||
mountPath: "/data"
|
||||
},
|
||||
if _config.tls.secretName != "" {
|
||||
name: "tls"
|
||||
mountPath: _config.tls.certPath
|
||||
readOnly: true
|
||||
},
|
||||
]
|
||||
resources: _config.resources
|
||||
if _config.securityContext != _|_ {
|
||||
securityContext: _config.securityContext
|
||||
}
|
||||
},
|
||||
]
|
||||
nodeSelector: _config.nodeSelector
|
||||
affinity: _config.affinity
|
||||
tolerations: _config.tolerations
|
||||
if _config.affinity != _|_ {
|
||||
affinity: _config.affinity
|
||||
}
|
||||
if _config.tolerations != _|_ {
|
||||
tolerations: _config.tolerations
|
||||
}
|
||||
volumes: [
|
||||
{
|
||||
name: "data"
|
||||
emptyDir: {}
|
||||
},
|
||||
if _config.tls.secretName != "" {
|
||||
name: "tls"
|
||||
secret: {
|
||||
secretName: _config.tls.secretName
|
||||
}
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -6,10 +6,10 @@ import (
|
||||
|
||||
#hpaConfig: {
|
||||
enabled: *false | bool
|
||||
cpu: *0 | int
|
||||
cpu: *99 | int
|
||||
memory: *"" | string
|
||||
minReplicas: int
|
||||
maxReplicas: int
|
||||
minReplicas: *1 | int
|
||||
maxReplicas: *1 | int
|
||||
}
|
||||
|
||||
#HorizontalPodAutoscaler: autoscaling.#HorizontalPodAutoscaler & {
|
||||
|
||||
+29
-30
@@ -5,21 +5,11 @@ import (
|
||||
)
|
||||
|
||||
#ingressConfig: {
|
||||
svcName: string
|
||||
svcPort: int
|
||||
enabled: *false | bool
|
||||
className: *"" | string
|
||||
tls: [{
|
||||
hosts: [string]
|
||||
secretName: string
|
||||
}]
|
||||
hosts: [{
|
||||
host: "podinfo.local"
|
||||
paths: [{
|
||||
path: "/"
|
||||
pathType: "ImplementationSpecific"
|
||||
}]
|
||||
}]
|
||||
enabled: *false | bool
|
||||
annotations?: {[ string]: string}
|
||||
className?: string
|
||||
tls: *false | bool
|
||||
host: string
|
||||
}
|
||||
|
||||
#Ingress: netv1.#Ingress & {
|
||||
@@ -27,22 +17,31 @@ import (
|
||||
apiVersion: "networking.k8s.io/v1"
|
||||
kind: "Ingress"
|
||||
metadata: _config.meta
|
||||
spec: netv1.#IngressSpec & {
|
||||
ingressClassName: _config.ingress.className
|
||||
tls: [ for t in _config.ingress.tls {
|
||||
hosts: t.hosts
|
||||
secretName: t.secretName
|
||||
if _config.ingress.annotations != _|_ {
|
||||
metadata: annotations: _config.ingress.annotations
|
||||
}
|
||||
spec: netv1.#IngressSpec & {
|
||||
rules: [{
|
||||
host: _config.ingress.host
|
||||
http: {
|
||||
paths: [{
|
||||
pathType: "Prefix"
|
||||
path: "/"
|
||||
backend: service: {
|
||||
name: _config.meta.name
|
||||
port: name: "http"
|
||||
}
|
||||
}]
|
||||
}
|
||||
}]
|
||||
rules: [ for h in _config.ingress.hosts {
|
||||
host: h.host
|
||||
http: paths: [ for p in h.paths {
|
||||
path: p.path
|
||||
pathType: p.pathType
|
||||
backend: service: {
|
||||
name: _config.meta.name
|
||||
port: number: _config.service.externalPort
|
||||
}
|
||||
if _config.ingress.tls {
|
||||
tls: [{
|
||||
hosts: [_config.ingress.host]
|
||||
secretName: "\(_config.meta.name)-cert"
|
||||
}]
|
||||
}]
|
||||
}
|
||||
if _config.ingress.className != _|_ {
|
||||
ingressClassName: _config.ingress.className
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+20
-19
@@ -10,8 +10,6 @@ import (
|
||||
httpPort: *9898 | int
|
||||
metricsPort: *9797 | int
|
||||
grpcPort: *9999 | int
|
||||
grpcService: "podinfo" | string
|
||||
nodePort: *31198 | int
|
||||
}
|
||||
|
||||
#Service: corev1.#Service & {
|
||||
@@ -20,24 +18,27 @@ import (
|
||||
kind: "Service"
|
||||
metadata: _config.meta
|
||||
spec: corev1.#ServiceSpec & {
|
||||
type: "ClusterIP"
|
||||
type: _config.service.type
|
||||
selector: _config.selectorLabels
|
||||
ports: [{
|
||||
name: "http"
|
||||
port: _config.service.externalPort
|
||||
targetPort: _config.service.httpPort
|
||||
protocol: "TCP"
|
||||
}, if _config.tls.enabled == true {
|
||||
name: "https"
|
||||
port: _config.tls.port
|
||||
targetPort: "https"
|
||||
protocol: "TCP"
|
||||
}, if _config.service.grpcPort != _|_ {
|
||||
name: "grpc"
|
||||
port: _config.service.grpcPort
|
||||
targetPort: "grpc"
|
||||
protocol: "TCP"
|
||||
},
|
||||
ports: [
|
||||
{
|
||||
name: "http"
|
||||
port: _config.service.externalPort
|
||||
targetPort: "\(name)"
|
||||
protocol: "TCP"
|
||||
},
|
||||
{
|
||||
name: "http-metrics"
|
||||
port: _config.service.metricsPort
|
||||
targetPort: "\(name)"
|
||||
protocol: "TCP"
|
||||
},
|
||||
{
|
||||
name: "grpc"
|
||||
port: _config.service.grpcPort
|
||||
targetPort: "\(name)"
|
||||
protocol: "TCP"
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package podinfo
|
||||
#serviceMonConfig: {
|
||||
enabled: *false | bool
|
||||
interval: *"15s" | string
|
||||
matchLabels: {}
|
||||
}
|
||||
|
||||
#ServiceMonitor: {
|
||||
@@ -14,10 +13,10 @@ package podinfo
|
||||
spec: {
|
||||
endpoints: [{
|
||||
path: "/metrics"
|
||||
port: "http"
|
||||
port: "http-metrics"
|
||||
interval: _config.serviceMonitor.interval
|
||||
}]
|
||||
namespaceSelector: matchNames: _config.meta.namespace
|
||||
selector: matchLabels: _config.selectorLabels
|
||||
selector: matchLabels: _config.meta.labels
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user