Reputation: 453
I am trying to achieve the following using ansible. I have a kubernetes deployment file that I want to add a dynamic amount of volumes and volumeMounts to.
The approach I am currently taking is putting the parts I want to patch in a variable, then try use the combine pipe to merge the different parts together. However instead of adding the parts together like this:
volumeMounts:
- name: nfs-standard
mountPath: /mnt/standard
readOnly: true
- name: nfs-share2
mountPath: /mnt/share2
readOnly: true
- name: nfs-system
mountPath: /mnt/system
readOnly: true
It replaces the previous one so I end up having just one. Furthermore, when I try to combine this with the final yaml, it removes other parts.
This is how I tried solving it in ansible, this part if being looped over X amount of times depending on the amount of nfs shares
- name: "loop over fs types"
set_fact:
patch:
spec:
template:
spec:
containers:
- name: fsmonitor
volumeMounts:
- name: "nfs-{{ NFS_NAME }}"
mountPath: "{{ NFS_MOUNT_PATH }}"
readOnly: true
volumes:
- name: "nfs-{{ NFS_NAME }}"
nfs:
server: "{{ NFS_SHARE_IP[0] }}"
path: "{{ NFS_PATH[0] }}"
- name:
set_fact:
deployment: "{{ deployment | combine(patch, recursive=True) }}"
It's missing the image and such which, when deployed to kubernetes, results in an unprocessable entity
ok: [gitlab-deploy] => {
"deployment": {
"apiVersion": "apps/v1",
"kind": "Deployment",
"metadata": {
"name": "fsmonitor-deploy"
},
"spec": {
"template": {
"spec": {
"containers": [
{
"name": "fsmonitor",
"volumeMounts": [
{
"mountPath": "/mnt/nfs",
"name": "nfs-system",
"readOnly": true
}
]
}
],
"volumes": [
{
"name": "nfs-system",
"nfs": {
"path": "/nfs/system",
"server": "XXXXXXXXX"
}
}
]
}
}
}
}
}
Here is a part of the full deployment (the container part)
[
{
"image": "XXXXXXXXXXXXXXXXX",
"imagePullPolicy": "Always",
"livenessProbe": {
"httpGet": {
"path": "/metrics",
"port": XXXX
},
"initialDelaySeconds": 3,
"periodSeconds": 3
},
"name": "fsmonitor",
"ports": [
{
"containerPort": XXXX
}
],
"resources": {
"limits": {
"cpu": "700m",
"memory": "700Mi"
},
"requests": {
"cpu": "200m",
"memory": "200Mi"
}
},
"volumeMounts": null
}
],
I hope someone can help me with what I am trying to do, I come from a software engineering background and wrapping my head around how ansible works is difficult at times.
Upvotes: 1
Views: 939
Reputation: 996
I would take a different approach - create variables with the nfs details and loop over those in a Jinja template. Jinja templates work well with Kubernetes resources and will allow you to use standard syntax like for loops, if/then statements and so on to create your resource files.
While it's probably possible to do something with variables and filters it's going to be far more complex and difficult to maintain.
Lets say your tasks looks like this:
- name: List of volume mounts
set_fact:
volume_details:
- name: nfs-standard
mountPath: /mnt/standard
readOnly: true
server: server1
- name: nfs-share2
mountPath: /mnt/share2
readOnly: true
server: server1
- name: nfs-system
mountPath: /mnt/system
readOnly: true
server: server2
- name: Create deployment file
template:
src: template.j2
dest: "/tmp/template.yml"
mode: 0755
Create a file called deployment.j2 in the templates folder:
---
deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: fsmonitor-deploy
spec:
template:
spec:
containers:
- name: fsmonitor
volumeMounts:
{% for volume in volume_details %}
- mountPath: "{{ volume.mountPath }}"
name: "{{ volume.name }}"
readOnly: "{{ volume.readOnly }}"
{% endfor %}
volumes:
{% for volume in volume_details %}
- name: "{{ volume.name }}"
nfs:
path: "{{ volume.mountPath }}"
server: "{{ volume.server }}"
{% endfor %}
After the run deployment.yml will be created:
---
deployment:
apiVersion: apps/v1
kind: Deployment
metadata:
name: fsmonitor-deploy
spec:
template:
spec:
containers:
- name: fsmonitor
volumeMounts:
- mountPath: "/mnt/standard"
name: "nfs-standard"
readOnly: "True"
- mountPath: "/mnt/share2"
name: "nfs-share2"
readOnly: "True"
- mountPath: "/mnt/system"
name: "nfs-system"
readOnly: "True"
volumes:
- name: "nfs-standard"
nfs:
path: "/mnt/standard"
server: "server1"
- name: "nfs-share2"
nfs:
path: "/mnt/share2"
server: "server1"
- name: "nfs-system"
nfs:
path: "/mnt/system"
server: "server2"
Take a look at the Jinja documentation, it's quite flexible for this kind of application.
https://jinja.palletsprojects.com/en/2.11.x/
Upvotes: 2