How can I check if a k8s secret exists in a Helm chart/k8s template, or use a default value? - kubernetes

I have a template part like:
spec:
containers:
- name: webinspect-runner-{{ .Values.pipeline.sequence }}
...
env:
- name: wi_base_url
valueFrom:
secretKeyRef:
name: webinspect
key: wi-base-url
- name: wi_type
valueFrom:
secretKeyRef:
name: webinspect
key: wi-type
The webinspect/wi_type secret may be missing. I want the container also don't have the wi_type envvar or get a default value (better) when the secret is missing, but k8s just reports CreateContainerConfigError: couldn't find key wi-type in Secret namespace/webinspect and the pod fails.
Is there a way to use a default value, or skip the block if the secret does not exist?

Two options, the first is add optional: true to the secretKeyRef block(s) which makes it skip. The second is a much more complex approach using the lookup template function in Helm. Probably go with the first :)

Related

Use fieldRef in Kubernetes configMap

I have the following environment variable in my Kubernetes template:
envFrom:
- configMapRef:
name: configmap
env:
- name: MACHINENAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
I would like to use the value from 'fieldRef' in a config map instead. Would this kind of modification be possible?
In other words, I want to add the 'MACHINENAME' environment variable to the config map, so I don't have to use the 'env:' block.
You cannot do this in the way you describe.
A ConfigMap only contains fixed string-key/string-value pairs. You cannot embed a more complex structure into a ConfigMap, or say that a ConfigMap value will be resolved using the downward API when a Pod is created. The node name of the pod, and most of the other downward API information, will be different for each pod using the ConfigMap (and likely even for each replica of the same deployment) and so there is no fixed value you can put into a ConfigMap.
You tagged this question with the Helm deployment tool. If you're using Helm, and you're simply trying to avoid repeating this boilerplate in every Deployment spec, you can write a helper template that includes this definition
{{/* templates/_helpers.tpl */}}
{{- define "machinename" -}}
- name: MACHINENAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
{{- end -}}
Now in your Deployment spec, you can include this template rather than retyping the whole YAML block.
containers:
- envFrom:
- configMapRef:
name: configmap
env:
{{ include "machinename . | indent 6 }}
(The exact indent value will depend on the context where you include it, and should be two more than the number of spaces at the start of the env: line. It is important that the line containing indent not itself be indented.)
Yes, using a ConfigMap would be possible. This Stack Overflow post is quite old, but has some good information in:
Advantage of using configmaps for environment variables with Kubernetes/Helm
You would need to either mount the ConfigMap as a volume or consume via environment variables by using envFrom. This guide provides both examples:
https://matthewpalmer.net/kubernetes-app-developer/articles/ultimate-configmap-guide-kubernetes.html
You can use the volume mount option and merge different configmap or env
volumes:
- name: all-in-one
projected:
sources:
- secret:
name: mysecret
items:
- key: username
path: my-group/my-username
- downwardAPI:
items:
- path: "labels"
fieldRef:
fieldPath: metadata.labels
- path: "cpu_limit"
resourceFieldRef:
containerName: container-test
resource: limits.cpu
- configMap:
name: myconfigmap
items:
- key: config
path: my-group/my-config
Ref : https://kubernetes.io/docs/concepts/storage/projected-volumes/
initContainer
There is another alternative you can follow if you want to merge those values.
Either you merge configmap & fieldRef with InitContainer as it's your Node name so, have to get value first and edit/add value to configmap with initContainer.

Same secret for different services in k8s

I have a situation when I want to use one Opaque secret in different service
the only difference is that key should have different name:
f.e.
service1 should have env.variable named TOKEN and value SUperPassword111!
service2 should have env.variable named SRV__TOKEN and same value SUperPassword111!
Is it possible to use following secret for those those two service?
Here is the YAML for the secret
kind: Secret
apiVersion: v1
metadata:
name: some_secret
immutable: false
data:
TOKEN: U1VwZXJQYXNzd29yZDExMSEK
type: Opaque
The name of an environment variable is specified within the container-spec while the value is referenced with secretKeyRef which specifies the secret to use and the key within this particular secret.
In other words, the name of the environment variable and the key as used in a secret are entirely independent. So, if I understood your question correctly, the answer to it is; yes it is possible.
See https://kubernetes.io/docs/concepts/configuration/secret/ for a detailed explanation and a full example for referencing a secret from a pod.
Here a simple excerpt tailored to your question:
container-spec for "service1"
...
containers:
- name: service1
image: service1-image
env:
- name: TOKEN # the name of the env within your container
valueFrom:
secretKeyRef:
name: some_secret
key: TOKEN # the name as specified in the secret
...
container-spec for "service2"
...
containers:
- name: service1
image: service1-image
env:
- name: SRV__TOKEN # the name of the env within your container
valueFrom:
secretKeyRef:
name: some_secret
key: TOKEN # the name as specified in the secret
...

Is it possible to retrieve pod name from values.yaml file of helm chart?

Quite new to Helm. Currently, I create an env variable in a way that when I deploy my pod, I am able to see the pod name in the environment variables list. This can be done like so in the template file:
containers:
- name: my_container
env:
- name: POD_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name
Is it possible to do something similar in the values.yaml file (maybe in an extraEnv field?) and then use this value in the .tpl? Other configurations, like configmap names, depend on it, in order to be unique between pods and I want to easily retrieve the value like so:
volumes:
- name: my_vol
configMap:
name: {{ .Values.pathto.extraEnv.podname }}
Thanks in advance!

Can an OpenShift template env variable be used in the name of a secretKeyRef?

I have a template and a deployment in it, One of my deployment's env variables is a value from a secret that contains the name of the namespace that just used the template.
The secret must contain the name of the namespace, I can't change it.
I know that it is possible to use env variables as value of different env variables. Looks like this:
env:
- name: MY_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: FULL_NAME
value: ${MY_NAME}.$(MY_NAMESPACE)
This way, if my namespace's name is app and the MY_NAME parameter is dan:
echo $FULL_NAME
> dan.app
But I want to use that name as a reference to a secret name. Like this:
env:
- name: MY_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: FULL_NAME_SECRET
valueFrom:
secretKeyRef:
name: ${MY_NAME}.$(MY_NAMESPACE)
key: app_name
I get an event that says:
Pod "test-0" is invalid[spec.containers[0].env[1].valueFrom.secretKeyRef.name: Invalid value: "dan.$(MY_NAMESPACE)": a DNS-1123 subdomain must consist of lower case alphanumeric characters, '-' or '.', and must start with an alphanumeric character
Well basically it does not translate the $(MY_NAMESPACE) to the actual value of its env variable.
The secretKeyRef: secret name must be a fixed string. Variable expansion only happens in a couple of places in the pod spec (in env: values, command:, and args:, but nowhere else).
For your immediate problem, it may help to recognize that a Pod and any matching Secret must be in the same namespace. You don't need to include the namespace name in the Secret name, and there's no way to refer to a Secret in a different namespace if you needed to.
- name: FULL_NAME_SECRET
valueFrom:
secretKeyRef:
name: dan # always in the same namespace
key: app_name
More broadly, you can use a tool like Helm to fill in some of these values from templates. These can use data known at install time to construct "fixed strings" that can be submitted to Kubernetes.
{{/* In a Helm chart's templates/deployment.yaml */}}
- name: FULL_NAME_SECRET
valueFrom:
secretKeyRef:
name: {{ include "dan.name" . }}.{{ .Release.Namespace }}
key: app_name
In this the parts in the curly braces {{ ... }} are expanded by Helm's template engine. .Release.Namespace is the namespace into which you're installing. include "dan.name" . calls a helper template that constructs the "dan" name, in a way that supports multiple installations in the same namespace.

Using different Secrets in sts replicas

I'm trying to use different secrets on a StatefulSet, based on the index o the pods.
Here is the things I tried:
env:
- name: POD_NAME
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.name
- name: SECRET_KEY
valueFrom:
secretKeyRef:
key: key
name: mysecret-$(POD_NAME)
- name: SECRET_HOST
value: myhost-$(POD_NAME)
However, mysecret-$(POD_NAME) is not correctly sobstituted as parameter, while myhost-$(POD_NAME) acts correcly.
How can I solve this problem? The goal is to set different variables from secret/configmaps on different replicas of the StatefulSet.
AFAIK this is not supported. The only volumes you can have differ are the PVs. Instead you would use a single secret with keys or whatnot based on the pod index, and write your software to read from the correct key.