I need to inject container port from an environment variable inside my pod. How to do that?
Have been through the documentation, Links:- 1. https://kubernetes.io/docs/tasks/inject-data-application/define-environment-variable-container/ 2. https://kubernetes.io/docs/tasks/inject-data-application/environment-variable-expose-pod-information/
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
namespace: default
spec:
containers:
- name: nginx-container
image: nginx
ports:
- containerPort: $(MY_CONTAINER_PORT)
env:
- name: MY_CONTAINER_PORT
value: 80
error: error validating "nginx-pod-exposed-through-env.yaml": error validating data: ValidationError(Pod.spec.containers[0].ports[0].containerPort): invalid type for io.k8s.api.core.v1.ContainerPort.containerPort: got "string", expected "integer"; if you choose to ignore these errors, turn validation off with --validate=false
Below example has an environment variable "PASSWORD"
apiVersion: v1
kind: Pod
metadata:
name: ubuntu
spec:
containers:
- name: ubuntu
image: ubuntu:latest
command: [ "/bin/bash", "-c", "--" ]
args: [ "while true; do sleep 30; done;" ]
env:
- name: PASSWORD
value: "password"
You can't use environment variables defined for the pod to be used to expose the port. Kubernetes expects the value of container port to be integer, but since you gave $(MY_CONTAINER_PORT), it says string values are not allowed.
The right configuration would be,
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
namespace: default
spec:
containers:
- name: nginx-container
image: nginx
ports:
- containerPort: 80
However, if you still need environment variables to be specified as containerPort, its better to use kubernetes package manager like helm, or run a shell script to your yaml before deploying to kubernetes, preferrably with envsubstr
that will resolve the environment variable and regenerate the yaml file with the env variable substituted for containerPort. Perhaps this github link might help you why kubectl will never support variable substitution.
A way to accomplish this would be to use a templating tool such as ytt. With ytt you would turn your manifest into a template like:
#@ load("@ytt:data", "data")
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
namespace: default
spec:
containers:
- name: nginx-container
image: nginx
ports:
- containerPort: #@ data.values.port
And then supply a values.yml
like:
#@data/values
---
port: 8080
Assuming the original template is named test.yml
we could run ytt
like so to generate the output:
$ ytt -f test.yml -f values.yml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
namespace: default
spec:
containers:
- name: nginx-container
image: nginx
ports:
- containerPort: 8080
The ytt utility then lets us override the data values one the command line with --data-value
(or -v
for short). An example changing to port 80:
$ ytt -v port=80 -f test.yml -f values.yml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
namespace: default
spec:
containers:
- name: nginx-container
image: nginx
ports:
- containerPort: 80
Your original question sounded like you wanted to use environment variables. This is supported with --data-values-env
. An example using prefix MYVAL
:
$ export MYVAL_port=9000
$ ytt --data-values-env MYVAL -f test.yml -f values.yml
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
namespace: default
spec:
containers:
- name: nginx-container
image: nginx
ports:
- containerPort: 9000
You can then combine ytt
and kubectl
to create and apply resources:
ytt --data-values-env MYVAL -f test.yml -f values.yml | kubectl apply -f-
Additional information on injecting data into ytt templates is at https://github.com/k14s/ytt/blob/master/docs/ytt-data-values.md.