How to overwrite file in pods container in Kubernetes deployment file? - elasticsearch

I want to overwrite the file on the pod container. Right now I have elasticsearch.yml at location /usr/share/elasticsearch/config.
I was trying to achieve that with initContainer at kubernetes deployment file, so I added something like:
- name: disabled-the-xpack-security
image: busybox
command:
- /bin/sh
- -c
- |
sleep 20
rm /usr/share/elasticsearch/config/elasticsearch.yml
cp /home/x/IdeaProjects/BD/infra/istio/kube/elasticsearch.yml /usr/share/elasticsearch/config/
securityContext:
privileged: true
But this doesn't work, error looks like:
rm: can't remove '/usr/share/elasticsearch/config/elasticsearch.yml': No such file or directory
cp: can't stat '/home/x/IdeaProjects/BD/infra/istio/kube/elasticsearch.yml': No such file or directory
I was trying to use some echo "some yaml config" >> elasticsearch.yml, but this kind of workarounds doesn't work, because I was able to keep proper yaml formatting.
Do you have any suggestions, how can I do this?

As stated by Arman in the comments, you can create a ConfigMap with the contents of /home/x/IdeaProjects/BD/infra/istio/kube/elasticsearch.ymland mount it as a volume in the deployment.
To create the config map from your file you can run:
kubectl create configmap my-es-config --from-file=/home/x/IdeaProjects/BD/infra/istio/kube/elasticsearch.yml
This will create a ConfigMap inside your kubernetes cluster with the yaml file.
You can then use that and add the volume mount to your deployment as:
containers:
- name: elasticsearch
image: k8s.gcr.io/busybox
.
.
.
volumeMounts:
- name: config-volume
mountPath: /usr/share/elasticsearch/config/
volumes:
- name: config-volume
configMap:
name: my-es-config
Notes
It is recommended to create your ConfigMap as yaml as well. More information here
Mounting a configmap directly on /usr/share/elasticsearch/config/, will replace everything inside that path and place the config file from the configmap. If that causes an issue, you might want to mount it at another location and then copy it.

Note if you don't want to override everything in the mounted directory you could mount the file only using "subPath" in whatever directory you want.
https://kubernetes.io/docs/concepts/storage/volumes/#using-subpath

Related

How to mount a host volume in Kubernetes running on Docker Desktop (Windows 10) backed by WSL2?

I've figured out the syntax to mount a volume (Kubernetes YAML):
apiVersion: v1
kind: Pod
metadata:
...
spec:
containers:
- name: php
volumeMounts:
- mountPath: /app/db_backups
name: db-backups
readOnly: true
volumes:
- hostPath:
path: /mnt/c/Users/Mark/PhpstormProjects/proj/db_backups
type: DirectoryOrCreate
name: db-backups
And the volume does show when I drop into a shell:
kubectl --context docker-desktop exec --stdin --tty deploy/app-deployment-development -cphp -nmyns -- /bin/bash
But the db_backups directory is empty, so I guess the volume is backed by nothing -- it's not finding the volume on my Windows host machine.
I've tried setting the host path like C:\Users\Mark\PhpstormProjects\proj\db_backups but if I do that then my Deployment fails with a CreateContainerError:
Error: Error response from daemon: invalid volume specification: 'C:\Users\Mark\PhpstormProjects\proj\db_backups:/app/db_backups:ro'
So I guess it doesn't like the Windows-style filepath.
So what then? If neither style of path works, how do I get it to mount?
From here it is clear that, for WSL2 we need to mention the specific path before we are actually giving the path we desired in the host machine.
In your file you are giving like path: /mnt/c/Users/Mark/PhpstormProjects/proj/db_backups but you need to mention the path like this path: /run/desktop/mnt/host/path_of_directory_in_local_machine. The key is we need to mention /run/desktop/mnt/host/ before we are going to give the actual path to the directory.
You gave the type: DirectoryOrCreate in the above file, so that is creating an empty directory in the path you mentioned. Because it is not actually going to your desired path.
So try with this
apiVersion: v1
kind: Pod
metadata:
...
spec:
containers:
- name: php
volumeMounts:
- mountPath: /app/db_backups
name: db-backups
readOnly: true
volumes:
- hostPath:
path: /run/desktop/mnt/host/c/Users/Mark/PhpstormProjects/proj/db_backups
#In my case tested with path: /run/desktop/mnt/host/d/K8-files/voldir
type: DirectoryOrCreate
name: db-backups
It worked in our case, we created a directory in 'd' drive so we used this path: /run/desktop/mnt/host/d/K8-files/voldir. So try giving /run/desktop/mnt/host/ before the actual path.
For more information refer this Link

openshift set environment variable from a file

I have a mount volume has a file urls.txt with database source url, like
databasesource: mysql://xxxx
and in my springboot application which will be running as a container in a openshift pod, and in the application I need to change the SPRING_DATASOURCE_URL as mentioned in the file above, here is what I want to achieve in my template file
env:
- name: SPRING_DATASOURCE_URL
valueFrom:
mount:
name: my-volume
key: databasesource
volumeMounts:
- name: my-volume
mountPath: /someDir
I know we can valueFrom configMap or secret, but I want to achieve via a volumeMount
if you can use below format in
urls.txt
databasesource=mysql://xxxx
as part of your container start you run
source /somedir/urls.txt
which will load the key & values in env. which can be further used.
The problem is resolved by a Springboot2.0 feature: https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.external-config.files.importing-extensionless

Spring Boot: override application.yml properties from Kubernetes ConfigMap

I need to oveeride some of properties defined in a application.yml of Spring Boot application running in k8s. How can I do this? The only way I found is to mount whole application.yml but I only need to override one property.
Could be doable in another way, that's why i'm answering again.
Do it in an easy way.
Create your application.yml in a configmap and mount it as a sub directory called config into the same directory where the spring boot jar ins located.
The documentation of spring boot (external application properties) says:
Spring Boot will automatically find and load application.properties and application.yaml files from the following locations when your application starts:
The classpath root
The classpath /config package
The current directory
The /config subdirectory in the current directory
Immediate child directories of the /config subdirectory
Which means we don't have to take care of setting anything. It should find the config inside the subdirectory config.
apiVersion: v1
kind: ConfigMap
metadata:
name: spring-application-config
data:
application.yml: |
spring:
application:
name: This is just an example, add as many values as you want.
pod.yaml:
...
volumeMounts:
- name: spring-application-config
mountPath: /app/config
- name: spring-application-config
configMap:
name: spring-application-config
...
Assuming that your spring boot jar file is located in the path /app
Spring Boot Apps should override properties in the configuration files (aka, in their application.yml most of the times) with environment variables.
Assuming the App is deployed on Kubernetes with a Pod (but it doesn't matter, Deployments, StatefulSets, Jobs are all the same regarding environment) you can inject environment variables inside the container by either directly assigning them to the Deployment itself, or with a ConfigMap (or a Secret, should the property be more secure and masked)
apiVersion: v1
kind: Pod
metadata:
name: example
spec:
containers:
- name: example-container
image: example-image:latest
env:
- name: THIS_IS_AN_ENV_VARIABLE
value: "Hello from the environment"
- name: spring.persistence.url
value: "The persistence url, for example"
Even better, you can inject all the content of a ConfigMap as environment variables:
apiVersion: v1
kind: ConfigMap
metadata:
name: example-config
data:
spring.persistence.url: "your persistence url"
spring.mail.user: "your mail user"
And then your Pod:
apiVersion: v1
kind: Pod
metadata:
name: example
spec:
containers:
- name: example-container
image: example-image:latest
envFrom:
- configMapRef:
name: example-config
Inside the container, the variables will be in the environment.. and Spring should use them to override variables with same name which are defined (or maybe not even defined) in your application.yml
For more info:
https://kubernetes.io/docs/tasks/configure-pod-container/configure-pod-configmap/
https://kubernetes.io/docs/tasks/inject-data-application/environment-variable-expose-pod-information/
https://docs.spring.io/spring-boot/docs/1.3.3.RELEASE/reference/html/boot-features-external-config.html
We had to do something similar. And i explain you how we did. Possibly this helps.
If you can modify your Dockerfile then create an entrypoint.sh script.
It could contain the following:
entrypoint.sh
#!/bin/bash
set -e
# Source custom scripts, if any
if [ -d /etc/spring.d ]; then
for f in /etc/spring.d/*; do
if [ -x "$f" ]; then
echo "Running $f ..." >&2
"$f"
else
echo "Could not run $f, because it's missing execute permission (+x)." >&2
fi
done
unset f
fi
exec "$#"
The entrypoint.sh is executing custom scripts inside the /etc/spring.d directory on startup. You can put any exectuble script inside, whatever you want.
Inside the /etc/spring.d you can create a copy script which copies an application.yml into same directory where the spring boot jar file is located. Example follows.
Your Dockerfile could look like
FROM adoptopenjdk:15-jre
RUN mkdir /app
COPY application.jar /app/
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]
CMD ["java", "-jar", "/app/application.jar"]
If this is prepared, you can use a configMap to define the copy script and mount it to the directory /etc/spring.d
apiVersion: v1
kind: ConfigMap
metadata:
name: spring-d
data:
copy-yaml.sh: |
#!/bin/bash
cp /config/application.yml /app/application.yml
The copy script will take care, that you application.yaml (which will be mounted as a configMap as well) will be copied to the right place.
And a further configMap for your application.yml
apiVersion: v1
kind: ConfigMap
metadata:
name: app-yaml
data:
application.yml: |
spring:
application:
name: This is just an example, add as many values as you want.
Inside your pod yaml you could do something like this:
...
volumeMounts:
- name: spring-d
mountPath: /etc/spring.d
- name: app-yaml
mountPath: /config
- name: spring-d
configMap:
name: spring-d
defaultMode: 0777
- name: app-yaml
configMap:
name: app-yaml
...
THIS CODE IS CURRENTLY UNTESTED, IT'S JUST SHOWING YOU AN EXAMPLE HOW YOU COULD SOLVE YOUR PROBLEM IN A VERY FLEXIBLE WAY.
I used snippets from my scripts and copied it here together, so maybe there could be small mistakes inside. Please let me know.

Correctly override "settings.xml" in Jenkinsfile Maven build on kubernetes?

We are setting up a Jenkins-based CI pipeline on our Kubernetes cluster (Rancher if that matters) and up to now we have used the official maven:3-jdk-11-slim image for experiments. Unfortunately it does not provide any built-in way of overriding the default settings.xml to use a mirror, which we need - preferably just by setting an environment variable. I am not very familar with kubernetes so I may be missing something simple.
Is there a simple way to add a file to the image? Should I use another image with this functionality built in?
pipeline {
agent {
kubernetes {
yaml """
kind: Pod
metadata:
name: kaniko
spec:
containers:
- name: maven
image: maven:3-jdk-11-slim
command:
- cat
tty: true
- name: kaniko
.... etc
Summary: you can mount your settings.xml file on the pod at some specific path and use that file with command mvn -s /my/path/to/settings.xml.
Crou's ConfigMap approach is one way to do it. However, since the settings.xml file usually contains credentials, I would treat it as Secrets.
You can create a Secret in Kubernetes with command:
$ kubectl create secret generic mvn-settings --from-file=settings.xml=./settings.xml
The pod definition will be something like this:
apiVersion: v1
kind: Pod
metadata:
name: kaniko
spec:
containers:
- name: maven
image: maven:3-jdk-11-slim
command:
- cat
tty: true
volumeMounts:
- name: mvn-settings-vol
mountPath: /my/path/to
volumes:
- name: mvn-settings-vol
secret:
secretName: mvn-settings
Advanced/Optional: If you practice "Infrastructure as Code", you might want to save the manifest file for that secret for recovery. This can be achieved by this command after secret already created:
$ kubectl get secrets mvn-settings -o yaml
You can keep secrets.yml file but do not check into any VCS/Github repo since this version of secrets.yml contains unencrypted data.
Some k8s administrators may have kubeseal installed. In that case, I'd recommend using kubeseal to get encrypted version of secrets.yml.
$ kubectl create secret generic mvn-settings --from-file=settings.xml=./settings.xml --dry-run -o json | kubeseal --controller-name=controller --controller-namespace=k8s-sealed-secrets --format=yaml >secrets.yml
# Actually create secrets
$ kubectl apply -f secrets.yml
The controller-name and controller-namespace should be obtained from k8s administrators.
This secrets.yml contains encrypted data of your settings.xml and can be safely checked into VCS/Github repo.
If you want to override a file inside pod you can use ConfigMap to store the changed file and mount it instead of previous one.
You can create the ConfigMap from a file using
kubectl create configmap settings-xml --from-file=settings.xml
Your pod definition might look like this:
apiVersion: v1
kind: Pod
metadata:
name: kaniko
spec:
containers:
- name: maven
image: maven:3-jdk-11-slim
command:
- cat
tty: true
volumeMounts:
- name: config-settings
mountPath: /usr/share/maven/ref/settings.xml
volumes:
- name: config-settings
configMap:
# Provide the name of the ConfigMap containing the files you want
# to add to the container
name: settings-xml
...
This worked for me:
Install Config File Provider Plugin
Go to Manage Jenkins > Config File Management > Add a new config and insert here your settings.xml
In your jenkinsfile just put your rtMavenRun inside a configFileProvider block, and put the same fileId of the jenkins config file you created before
stage('Build Maven') {
steps {
configFileProvider([configFile(fileId: 'MavenArtifactorySettingId', variable: 'MAVEN_SETTINGS_XML')]) {
retry(count: 3) {
rtMavenRun(
tool: "Maven 3.6.2", //id specified in Global Tool Configuration
pom: 'pom.xml',
goals: '-U -s $MAVEN_SETTINGS_XML clean install',
)
}
}
}
}
this is exactly the pipeline that I used if you want to see more: https://gist.github.com/robertobatts/42da9069e13b61a238f51c36754de97b
If you versioned the settings.xml of the project with the code, it makes sense to build with mvn install -s settings.xml using sh step. It what I did at work. If settings.xml is not versioned with the project, it indeed makes sens to mount the file with Crou's solution.
To answer your question "Should I use another image with this functionality built in?" I would recommend to avoid a maximum to build custom images because you will end up having to maintain them

can't populate volume using configMap

I am trying run a spring boot application whose application.properties file will be used as a kubernetes configMap.
While deploying the app, I am adding a volume for this config file. But somehow, it is not creating properties file at mount path.
configMap name : integration-properties
Data :
application.properties:
http.stub.api.host=localhost
http.stub.api.port=8080
http.stub.api.path=stub-api
Deployment.yaml file :
volumeMounts:
- name: config-volume
mountPath: /opt/build/
volumes:
- name: config-volume
configMap:
name: integration-properties
items:
- key: application.properties
path: application.properties
When I run this application, it says, "/opt/build/application.properties" does not exists.
Please let me know for any further configuration required, if any and steps to do them.
So define configMap as:
data:
application.properties: |
http.stub.api.host=localhost
http.stub.api.port=8080
http.stub.api.path=stub-api
or you can also create directly from the application.properties file
kubectl create configmap integration-properties --from-file=application.properties=<path to file>
Your deployment.yaml file looks good to me there isn't any problem.

Resources