Schema initiation in Binami postgresql image for kubernetes cluster - postgresql

I am using bitnami PostgreSQL image to deploy StatfulSet inside my cluster node. I am not sure how to initiate schema for the PostgreSQL pod without building on top of bitnami image. I have looked around on the internet and someone said to use init containers but I am also not sure how exactly I would do that.

From the Github Readme of the Bitnami Docker image:
When the container is executed for the first time, it will execute the
files with extensions .sh, .sql and .sql.gz located at
/docker-entrypoint-initdb.d.
In order to have your custom files inside the docker image you can
mount them as a volume.
You can just mount such scripts under that directory using a ConfigMap volume. An example could be the following:
First, create the ConfigMap with the scripts, for example:
apiVersion: v1
kind: ConfigMap
metadata:
name: p-init-sql
labels:
app: the-app-name
data:
01_init_db.sql: |-
# content of the script goes here
02_second_init_db.sql: |-
# more content for another script goes here
Second, under spec.template.spec.volumes, you can add:
volumes:
- configMap:
name: p-init-sql
Then, under spec.template.spec.containers[0].volumeMounts, you can mount this volume with:
volumeMounts:
- mountPath: /docker-entrypoint-initdb.d
name: p-init-sql
With this said, you may find out that it is more easy to use HELM Charts.
Bitnami provides HELM Charts for all its images which simplify the usage of such images by a lot (as everything is ready to be installed and configured from a simple values.yaml file)
For example, there is such a chart for postgresql which you can find here and that can be of inspiration in how to configure the docker image even if you decide to write your own Kubernetes resources around that image.

Related

Best practice for adding app configuration files into kubernetes pods

I have the following setup:
An azure kubernetes cluster with some nodes where my application (consisting of multiple pods) is running.
I'm looking for a good way to make a project-specific configuration file (a few hundred lines) available for two of the deployed containers and their replicas.
The configuration file is different between my projects but the containers are not.
I'm looking for something like a read-only file mount in the containers, but haven't found an good way. I played around with persistent volume claims but there seems to be no automatic file placement possibility apart from copying (including uri and secret managing).
Best thing would be to have a possiblility where kubectl makes use of a yaml file to access a specific folder on my developer machine to push my configuration file into the cluster.
ConfigMaps are not a proper way to do it (because data has to be inside the yaml and my file is big and changing)
For volumes there seems to be no automatic way to place files inside them at creation time.
Can anybody guide me to a good solution that matches my situation?
You can use a configmap for this, but the configmap includes your config file. You can create a configmap with the content of your config file via the following:
kubectl create configmap my-config --from-file=my-config.ini=/path/to/your/config.ini
and the bind it as a volume in your pod:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: mypod
...
volumeMounts:
- name: config
mountPath: "/config"
readOnly: true
volumes:
- name: config
configMap:
name: my-config #the name of your configmap
Afterwards your config is available in your pod under /config/my-config.ini

How to install the JProfiler agent in a Kubernetes container?

What do I have to put into a container to get the agent to run? Just libjprofilerti.so on its own doesn't work, I get
Could not find agent.jar. The agentpath parameter must point to
libjprofilerti.so in an unmodified JProfiler installation.
which sounds like obvious nonsense to me - surely I can't have to install over 137.5 MB of files, 99% of which will be irrelevant, in each container in which I want to profile something?
-agentpath:/path/to/libjprofilerti.so=nowait
An approach is to use Init Container.
The idea is to have an image for JProfiler separate from the application's image. Use the JProfiler image for an Init Container; the Init Container copies the JProfiler installation to a volume shared between that Init Container and the other Containers that will be started in the Pod. This way, the JVM can reference at startup time the JProfiler agent from the shared volume.
It goes something like this (more details are in this blog article):
Define a new volume:
volumes:
- name: jprofiler
emptyDir: {}
Add an Init Container:
initContainers:
- name: jprofiler-init
image: <JPROFILER_IMAGE:TAG>
command: ["/bin/sh", "-c", "cp -R /jprofiler/ /tmp/"]
volumeMounts:
- name: jprofiler
mountPath: "/tmp/jprofiler"
Replace /jprofiler/ above with the correct path to the installation directory in the JProfiler's image. Notice that the copy command will create /tmp/jprofiler directory under which the JProfiler installation will go - that is used as mount path.
Define volume mount:
volumeMounts:
- name: jprofiler
mountPath: /jprofiler
Add to the JVM startup arguments JProfiler as an agent:
-agentpath:/jprofiler/bin/linux-x64/libjprofilerti.so=port=8849
Notice that there isn't a "nowait" argument. That will cause the JVM to block at startup and wait for a JProfiler GUI to connect. The reason is that with this configuration the profiling agent will receive its profiling settings from the JProfiler GUI.
Change the application deployment to start with only one replica. Alternatively, start with zero replicas and scale to one when ready to start profiling.
To connect from the JProfiler's GUI to the remote JVM:
Find out the name of the pod (e.g. kubectl -n <namespace> get pods) and set up port forwarding to it:
kubectl -n <namespace> <pod-name> port-forward 8849:8849
Start JProfiler up locally and point it to 127.0.0.1, port 8849.
Change the local port 8849 (the number to the left of :) if it isn't available; then, point JProfiler to that different port.
Looks like you are missing the general concept here.
It's nicely explained why to use containers in the official documentation.
The New Way is to deploy containers based on operating-system-level virtualization rather than hardware virtualization. These containers are isolated from each other and from the host: they have their own filesystems, they can’t see each others’ processes, and their computational resource usage can be bounded. They are easier to build than VMs, and because they are decoupled from the underlying infrastructure and from the host filesystem, they are portable across clouds and OS distributions.
Of course you don't need to install the libraries on each containers separately.
Kubernetes is using Volumes to share files between Containers.
So you can create a local type of Volume with JProfiles libs inside.
A local volume represents a mounted local storage device such as a disk, partition or directory.
You also need to keep in mind that if you share the Volume between Pods, those Pods will not know about JProfiles libs being attached. You will need to configure the Pod with correct environment variables/files through the use of Secrets or ConfigMaps.
You can configure your Pod to pull values from a Secret:
apiVersion: v1
kind: Pod
metadata:
labels:
context: docker-k8s-lab
name: jp-pod
name: jp-pod
spec:
containers:
- image: k8s.gcr.io/busybox
name: jp
envFrom:
secretRef:
name: jp-secret
jp-secret.yaml
apiVersion: v1
kind: Secret
metadata:
name: jp-secret
type: Opaque
data:
JPAGENT_PATH="-agentpath:/usr/local/jprofiler10/bin/linux-x64/libjprofilerti.so=nowait"
I hope this helps you.

How to execute scripts to import csv files inside a postgres deployed on a Kubernetes cluster?

I'm trying to deploy Postgres on my Kubernetes cluster and I have been successful to do this, but then I don't know how I can import my data which are in csv format. I already have the scripts which gets the path to data and create a database in a local instance of postgres, but when I deploy postgres on Kubernetes cluster then those scripts wont work because I can't see those script inside the pod.
I was looking for a solution to execute the scripts from host to inside the pod, or I can expose the directory of scripts and data to postgres pod.
I've found the hostpath solution, but I don't know how to define multiple volumes for a deployment. (I'm using Rook cluster to provision the volume)
Maybe a way to define a hostpath volume alongside a Rook volume so I can have access to the scripts and csv files inside the hostpath and then create the database inside the Rook volume.
I don't know of this makes sense, but I would appreciate if someone help me with this.
If you're using the official docker image, or an image that is derived from it but didn't destroy its entrypoint, then they have documentation about /docker-entrypoint-initdb.d/*.sql, with the tl;dr as
kind: ConfigMap
spec:
import_csv.sql: |
COPY my_table FROM '/whatever/path/you/want.csv' FORMAT csv /* etc */
---
kind: Pod
spec:
containers:
- volumeMounts:
- name: my-initdb-configmap
mountPath: /docker-entrypoint-initdb.d
readOnly: true
# ...
type deal

How do I inject binary files into a v1.7 pod

I have a 3rd party docker image that I want to use (https://github.com/coreos/dex/releases/tag/v2.10.0). I need to inject some customisation into the pod (CSS stylesheet and PNG images).
I haven't found a suitable way to do this yet. Configmap binaryData is not available before v1.10 (or 9, can't remember off the top of my head). I could create a new image and COPY the PNG files into the image, but I don't want the overhead of maintaining this new image - far safer to just use the provided image.
Is there an easy way of injecting these 2/3 files I need into the pod I create?
One way would be to mount 1 or more volumes into the desired locations within the pod, seemingly /web/static. This however would overwrite the entire directly so you would need to supply all the files not just those you wish to overwrite.
Example:
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- image: dex:2.10.0
name: dex
volumeMounts:
- mountPath: /web/static # the mount location within the container
name: dex-volume
volumes:
- name: dex-volume
hostPath:
path: /destination/on/K8s/node # path on host machine
There are a number of types of storage types for different cloud providers so take a look at https://kubernetes.io/docs/concepts/storage/volumes/ and see if theres something a little more specific to your environment rather than storing on disk.
For what it's worth, creating your own image would probably be the simplest solution.
You could mount your custom files into a volume, and additionally define a set of commands to run on pod startup (see here) to copy your files to their target path.
You of course need to also run the command that starts your service, in addition to the ones that copy your files.

K8S deployment executing shell scripts reading configuration data

In K8S, what is the best way to execute scripts in container (POD) once at deployment, which reads from confuguration files which are part of the deployment and seed ex mongodb once?
my project consist of k8s manifest files + configuration files
I would like to be able to update the config files locally and then redeploy via kubectl or helm
In docker-compose i could create a volume ponting at the directory where the config files resides and then in the command part execute bash -c cmds reading from the config files in the volume. How is this best done in K8S? I don't want to include the configuration files in a image via dockerfile, forcing me to rebuild the image before redeploying again via kubectl or helm
How is this best done in K8S?
There are several ways to skin a cat, but my suggestion would be to do the following:
Keep configuration in configMap and mount it as separate volume. Such a map is kept as k8s manifest, making all changes to it separate from docker build image - no need to rebuild or keep sensitive data within image. You can also use instead (or together with) secret in the same manner as configMap.
Use initContainers to do the initialization before main container is to be brought online, covering for your 'once on deployment' automatically. Alternatively (if init operation is not repeatable) you can use Jobs instead and start it when necessary.
Here is excerpt of example we are using on gitlab runner:
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
name: ss-my-project
spec:
...
template:
....
spec:
...
volumes:
- name: volume-from-config-map-config-files
configMap:
name: cm-my-config-files
- name: volume-from-config-map-script
projected:
sources:
- configMap:
name: cm-my-scripts
items:
- key: run.sh
path: run.sh
mode: 0755
# if you need to run as non-root here is how it is done:
securityContext:
runAsNonRoot: true
runAsUser: 999
supplementalGroups: [999]
containers:
- image: ...
name: ...
command:
- /scripts/run.sh
...
volumeMounts:
- name: volume-from-config-map-script
mountPath: "/scripts"
readOnly: true
- mountPath: /usr/share/my-app-config/config.file
name: volume-from-config-map-config-files
subPath: config.file
...
You can, ofc, mount several volumes from config maps or combine them in one single, depending on frequency of your changes and affected parts. This is example with two separately mounted configMaps just to illustrate the principle (and mark script executable), but you can use only one for all required files, put several files into one or put single file into each - as per your need.
Example of such configMap is like so:
apiVersion: v1
kind: ConfigMap
metadata:
name: cm-my-scripts
data:
run.sh: |
#!/bin/bash
echo "Doing some work here..."
And example of configMap covering config file is like so:
kind: ConfigMap
apiVersion: v1
metadata:
name: cm-my-config-files
data:
config.file: |
---
# Some config.file (example name) required in project
# in whatever format config file actually is (just example)
... (here is actual content like server.host: "0" or EFG=True or whatever)
Playing with single or multiple files in configMaps can yield result you want, and depending on your need you can have as many or as few as you want.
In docker-compose i could create a volume ponting at the directory where the config files resides and then in the command part execute bash -c cmds reading from the config files in the volume.
In k8s equivalent of this would be hostPath but then you would seriously hamper k8s ability to schedule pods to different nodes. This might be ok if you have single node cluster (or while developing) to ease change of config files, but for actual deployment above approach is advised.