I'm using GKE and Helm v3 and I'm trying to create/reserve a static IP address using ComputeAddress and then to create DNS A record with the previously reserved IP address.
Reserve IP address
apiVersion: compute.cnrm.cloud.google.com/v1beta1
kind: ComputeAddress
metadata:
name: ip-address
annotations:
cnrm.cloud.google.com/project-id: project-id
spec:
location: global
Get reserved IP address
kubectl get computeaddress ip-address -o jsonpath='{.spec.address}'
Create DNS A record
apiVersion: dns.cnrm.cloud.google.com/v1beta1
kind: DNSRecordSet
metadata:
name: dns-record-a
annotations:
cnrm.cloud.google.com/project-id: project-id
spec:
name: "{{ .Release.Name }}.example.com"
type: "A"
ttl: 300
managedZoneRef:
external: example-com
rrdatas:
- **IP-ADDRESS-VALUE** <----
Is there a way to reference the IP address value, created by ComputeAddress, in the DNSRecordSet resource?
Basically, I need something similar to the output values in Terraform.
Thanks!
Currently, there is not possible to assign different value as string (IP Address) on the field "rrdatas". So you are not able to "call" another resource like the IP Address created before. You need to put the value on format x.x.x.x
It's interesting that something similar exists for GKE Ingress where we can reference reserved IP address and managed SSL certificate using annotations:
annotations:
kubernetes.io/ingress.global-static-ip-name: my-static-address
I have no idea why there is not something like this for DNSRecordSet resource. Hopefully, GKE will introduce it in the future.
Instead of running two commands, I've found a workaround by using Helm's hooks.
First, we need to define Job as post-install and post-upgrade hook which will pick up the reserved IP address when it becomes ready and then create appropriate DNSRecordSet resource with it. The script which retrieves the IP address, and manifest for DNSRecordSet are passed through ConfigMap and mounted to Pod.
apiVersion: batch/v1
kind: Job
metadata:
name: "{{ .Release.Name }}-dns-record-set-hook"
annotations:
# This is what defines this resource as a hook. Without this line, the
# job is considered part of the release.
"helm.sh/hook": post-install,post-upgrade
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
spec:
template:
metadata:
name: "{{ .Release.Name }}-dns-record-set-hook"
spec:
restartPolicy: OnFailure
containers:
- name: post-install-job
image: alpine:latest
command: ['sh', '-c', '/opt/run-kubectl-command-to-set-dns.sh']
volumeMounts:
- name: volume-dns-record-scripts
mountPath: /opt
- name: volume-writable
mountPath: /mnt
volumes:
- name: volume-dns-record-scripts
configMap:
name: dns-record-scripts
defaultMode: 0777
- name: volume-writable
emptyDir: {}
ConfigMap definition with the script and manifest file:
apiVersion: v1
kind: ConfigMap
metadata:
creationTimestamp: null
name: dns-record-scripts
data:
run-kubectl-command-to-set-dns.sh: |-
# install kubectl command
apk add curl && \
curl -LO https://storage.googleapis.com/kubernetes-release/release/v1.15.1/bin/linux/amd64/kubectl && \
chmod u+x kubectl && \
mv kubectl /bin/kubectl
# wait for reserved IP address to be ready
kubectl wait --for=condition=Ready computeaddress/ip-address
# get reserved IP address
IP_ADDRESS=$(kubectl get computeaddress ip-address -o jsonpath='{.spec.address}')
echo "Reserved address: $IP_ADDRESS"
# update IP_ADDRESS in manifest
sed "s/##IP_ADDRESS##/$IP_ADDRESS/g" /opt/dns-record.yml > /mnt/dns-record.yml
# create DNS record
kubectl apply -f /mnt/dns-record.yml
dns-record.yml: |-
apiVersion: dns.cnrm.cloud.google.com/v1beta1
kind: DNSRecordSet
metadata:
name: dns-record-a
annotations:
cnrm.cloud.google.com/project-id: project-id
spec:
name: "{{ .Release.Name }}.example.com"
type: A
ttl: 300
managedZoneRef:
external: example-com
rrdatas:
- "##IP_ADDRESS##"
And, finally, for (default) Service Account to be able to retrieve the IP address and create/update DNSRecordSet, we need to assign some roles to it:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: dnsrecord-setter
rules:
- apiGroups: ["compute.cnrm.cloud.google.com"]
resources: ["computeaddresses"]
verbs: ["get", "list"]
- apiGroups: ["dns.cnrm.cloud.google.com"]
resources: ["dnsrecordsets"]
verbs: ["get", "create", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: dnsrecord-setter
subjects:
- kind: ServiceAccount
name: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: dnsrecord-setter