diff --git a/.gitignore b/.gitignore index 444829f..28c820e 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,9 @@ build/* .idea client-env.sh + +k8s/helm/certs/* +!k8s/helm/certs/aoc2024-http.crt +!k8s/helm/certs/aoc2024-http.key +!k8s/helm/certs/aoc2024-grpc.crt +!k8s/helm/certs/aoc2024-grpc.key diff --git a/Dockerfile b/Dockerfile index 0f26b34..1f156e4 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,6 +16,7 @@ ARG DAY COPY solutions/day${DAY} solutions/day${DAY} RUN go build -o app solutions/day${DAY}/main.go EXPOSE 3000 +EXPOSE 50051 HEALTHCHECK \ --start-interval=10s \ diff --git a/k8s/cert.config b/k8s/cert.config new file mode 100644 index 0000000..7b8483d --- /dev/null +++ b/k8s/cert.config @@ -0,0 +1,16 @@ +[req] +distinguished_name = req_distinguished_name +x509_extensions = v3_req +prompt = no + +[req_distinguished_name] +CN = *.aoc2024.se + +[v3_req] +keyUsage = critical, digitalSignature, keyEncipherment +extendedKeyUsage = serverAuth +subjectAltName = @alt_names + +[alt_names] +DNS.1 = *.aoc2024.se +DNS.2 = *.grpc.aoc2024.se \ No newline at end of file diff --git a/k8s/create-cert.sh b/k8s/create-cert.sh new file mode 100755 index 0000000..ae5e096 --- /dev/null +++ b/k8s/create-cert.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +# Creates a certificate for the Kubernetes ingress controller, +# this is required by the nginx-ingress controller to enable HTTP/2, +# and HTTP 2 is required for gRPC. +# +# The certificate is already created and checked into this repository, +# but the command is left here as documentation. The checked in certificate +# is valid for ~100 years. + +openssl req -x509 -nodes -days 36500 -newkey rsa:2048 \ + -keyout k8s/helm/certs/aoc2024.key -out k8s/helm/certs/aoc2024.crt \ + -subj "/CN=*.aoc2024.se/O=AdventOfCode" \ + -config ./k8s/cert.config diff --git a/k8s/helm/templates/day-deployment.yaml b/k8s/helm/templates/day-deployment.yaml index e2d5bc3..8560cef 100644 --- a/k8s/helm/templates/day-deployment.yaml +++ b/k8s/helm/templates/day-deployment.yaml @@ -31,7 +31,8 @@ spec: image: aoc2024-day{{ .day }} imagePullPolicy: Never ports: - - containerPort: {{ .containerPort | default 3000 }} + - containerPort: {{ .containerHttpPort | default 3000 }} + - containerPort: {{ .containerGrpcPort | default 50051 }} --- {{- end }} \ No newline at end of file diff --git a/k8s/helm/templates/day-ingress-grpc.yaml b/k8s/helm/templates/day-ingress-grpc.yaml new file mode 100644 index 0000000..c93b0d2 --- /dev/null +++ b/k8s/helm/templates/day-ingress-grpc.yaml @@ -0,0 +1,33 @@ +# An easier way to do this would be to generate one ingress resource +# per service, similar to how we have done for deployments and services. +# But now that I've got this working I think it's kinda clean, even though +# ImplementationSpecific pathType is bit of a code smell. + +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: aoc2024-ingress-grpc + annotations: + nginx.ingress.kubernetes.io/ssl-redirect: "true" + nginx.ingress.kubernetes.io/backend-protocol: "GRPC" +spec: + ingressClassName: nginx + tls: + - secretName: tls-certificate + hosts: + {{- range .Values.days}} + - "day{{ .day }}.grpc.{{ $.Values.hostname }}" + {{- end }} + rules: + {{- range .Values.days }} + - host: "day{{ .day }}.grpc.{{ $.Values.hostname }}" + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: aoc2024-day{{ .day }} + port: { number: 50051 } + {{- end }} + diff --git a/k8s/helm/templates/day-ingress.yaml b/k8s/helm/templates/day-ingress.yaml index 54a36b2..0c7233c 100644 --- a/k8s/helm/templates/day-ingress.yaml +++ b/k8s/helm/templates/day-ingress.yaml @@ -7,19 +7,18 @@ apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: aoc2024-ingress - annotations: - nginx.ingress.kubernetes.io/rewrite-target: /$2 spec: ingressClassName: nginx rules: - - http: + {{- range .Values.days }} + - host: "day{{ .day }}.{{ $.Values.hostname }}" + http: paths: - {{- range .Values.days }} - - path: /day{{ .day }}(/|$)(.*) - pathType: ImplementationSpecific + - path: / + pathType: Prefix backend: service: name: aoc2024-day{{ .day }} - port: - number: 3000 - {{- end }} \ No newline at end of file + port: { name: http } + {{- end }} + diff --git a/k8s/helm/templates/day-service.yaml b/k8s/helm/templates/day-service.yaml index 63cb83c..b1a7ef3 100644 --- a/k8s/helm/templates/day-service.yaml +++ b/k8s/helm/templates/day-service.yaml @@ -14,9 +14,13 @@ spec: day: "{{ .day }}" ports: - protocol: TCP - port: {{ .servicePort | default 3000 }} - targetPort: {{ .containerPort | default 3000 }} + port: {{ .serviceHttpPort | default 3000 }} + targetPort: {{ .containerHttpPort | default 3000 }} name: http + - protocol: TCP + port: {{ .serviceGrpcPort | default 50051 }} + targetPort: {{ .containerGrpcPort | default 50051 }} + name: grpc --- {{- end }} diff --git a/k8s/helm/templates/tls-certificate-secret.yaml b/k8s/helm/templates/tls-certificate-secret.yaml new file mode 100644 index 0000000..48921b6 --- /dev/null +++ b/k8s/helm/templates/tls-certificate-secret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: tls-certificate +type: kubernetes.io/tls +data: + tls.crt: {{ .Files.Get .Values.cert.crtFile | b64enc }} + tls.key: {{ .Files.Get .Values.cert.keyFile | b64enc }} diff --git a/k8s/helm/values.yaml b/k8s/helm/values.yaml index 2130583..fd7f7e4 100644 --- a/k8s/helm/values.yaml +++ b/k8s/helm/values.yaml @@ -1,150 +1,111 @@ +hostname: 'aoc2024.se' +cert: + crtFile: 'certs/aoc2024.crt' + keyFile: 'certs/aoc2024.key' + days: - day: '01' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 + # These parameters are optional, + # set here with default values as an example. + containerHttpPort: 3000 + serviceHttpPort: 3000 + containerGrpcPort: 50051 + serviceGrpcPort: 50051 - day: '02' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '03' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '04' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '05' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '06' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '07' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '08' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '09' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '10' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '11' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '12' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '13' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '14' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '15' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '16' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '17' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '18' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '19' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '20' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '21' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '22' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '23' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '24' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1 - day: '25' replicas: 2 - containerPort: 3000 - servicePort: 3000 version: v1