问题
My k8s namespace contains a Secret
which is created at deployment time (by svcat
), so the values are not known in advance.
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: my-database-credentials
data:
hostname: ...
port: ...
database: ...
username: ...
password: ...
A Deployment
needs to inject these values in a slightly different format:
...
containers:
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: my-database-credentials
key: jdbc:postgresql:<hostname>:<port>/<database> // ??
- name: DATABASE_USERNAME
valueFrom:
secretKeyRef:
name: my-database-credentials
key: username
- name: DATABASE_PASSWORD
valueFrom:
secretKeyRef:
name: my-database-credentials
key: password
The DATABASE_URL
needs to be composed out of the hostname
, port
, 'database` from the previously defined secret.
Is there any way to do this composition?
回答1:
Kubernetes allows you to use previously defined environment variables as part of subsequent environment variables. From the Kubernetes API reference docs:
Variable references $(VAR_NAME) are expanded using the previous defined environment variables in the container and any service environment variables.
So, you can first extract the required secret values into environment variables, and then compose the DATABASE_URL
with those variables.
...
containers:
env:
- name: DB_URL_HOSTNAME // part 1
valueFrom:
secretKeyRef:
name: my-database-credentials
key: hostname
- name: DB_URL_PORT // part 2
valueFrom:
secretKeyRef:
name: my-database-credentials
key: port
- name: DB_URL_DBNAME // part 3
valueFrom:
secretKeyRef:
name: my-database-credentials
key: database
- name: DATABASE_URL // combine
value: jdbc:postgresql:$(DB_URL_HOSTNAME):$(DB_URL_PORT)/$(DB_URL_DBNAME)
...
Note the round brackets $(...)
used for variable expansion.
回答2:
There are several ways to go (in increasing complexity order):
Mangle the parameter before putting it into the Secret (extend whatever you use to insert the info there).
Add a script into your Pod/Container to mangle the incoming parameters (environmental variables or command arguments) into what is needed. If you cannot or don't want to have your own container image, you can add your extra script as a Volume to the container, and set the Container's command field to override the container image start command.
Add a facility to your Kubernetes to do an automatic mangling "behind the scenes": you can add a Dynamic Admission Controller to do your mangling, or you can create a Kubernetes Operator and add a Custom Resource Definition (the operator would be told by the CRD which Secrets to watch for changes, and the operator would read the values and generate whatever other entries you want).
回答3:
You can do a couple of things I can think of:
Use a secrets volume and make a startup script that reads the secrets from the volume and then starts your application with the
DATABASE_URL
environment variable.apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: your_db_container command: [ "yourscript.sh" ] volumeMounts: - name: mycreds mountPath: "/etc/credentials" volumes: - name: mycreds secret: secretName: my-database-credentials defaultMode: 256
Pass the env variable in the
command
key of your container spec:apiVersion: v1 kind: Pod metadata: name: mypod spec: containers: - name: mypod image: your_db_container command: [ "/bin/sh", "-c", "DATABASE_URL=jdbc:postgresql:<hostname>:<port>/<database>/$(DATABASE_USERNAME):$(DATABASE_PASSWORD) /start/yourdb" ] env: - name: DATABASE_USERNAME valueFrom: secretKeyRef: name: my-database-credentials key: username - name: DATABASE_PASSWORD valueFrom: secretKeyRef: name: my-database-credentials key: password
来源:https://stackoverflow.com/questions/54173581/combining-multiple-k8s-secrets-into-an-env-variable