In this post, I would like to share how I was able to run Jira Data Center on Kubernetes in an effect way.
First of all, you need to have a storage class that supports dynamic provisioning. If you don’t have one, you can create one by following this how to articles: Use Glusterfs for Dynamic Volume Provisioning in Kubernetes. In this example, I use Glusterfs for my persistent data.
Second of all, you need to have a database ready. If not, you can quickly setup one on Kubernetes as well. I have the example for creating Postgres:
— | |
kind: PersistentVolumeClaim | |
apiVersion: v1 | |
metadata: | |
name: jira-postgres-pvc | |
labels: | |
app: jira-postgres | |
spec: | |
accessModes: | |
– ReadWriteOnce | |
resources: | |
requests: | |
storage: 5Gi | |
storageClassName: glusterfs |
— | |
apiVersion: v1 | |
kind: ConfigMap | |
metadata: | |
name: jira-postgres-config | |
labels: | |
app: jira-postgres | |
data: | |
POSTGRES_DB: jira | |
POSTGRES_USER: admin | |
POSTGRES_PASSWORD: admin |
— | |
apiVersion: apps/v1 | |
kind: Deployment | |
metadata: | |
name: jira-postgres | |
labels: | |
app: jira-postgres | |
spec: | |
replicas: 1 | |
selector: | |
matchLabels: | |
app: jira-postgres | |
template: | |
metadata: | |
labels: | |
app: jira-postgres | |
spec: | |
containers: | |
– name: postgres | |
image: postgres:9.6 | |
imagePullPolicy: "IfNotPresent" | |
ports: | |
– containerPort: 5432 | |
envFrom: | |
– configMapRef: | |
name: jira-postgres-config | |
volumeMounts: | |
– mountPath: /var/lib/postgresql/data | |
name: jira-postgres-pv | |
volumes: | |
– name: jira-postgres-pv | |
persistentVolumeClaim: | |
claimName: jira-postgres-pvc |
— | |
apiVersion: v1 | |
kind: Service | |
metadata: | |
name: jira-postgres | |
labels: | |
app: jira-postgres | |
spec: | |
type: ClusterIP | |
ports: | |
– port: 5432 | |
selector: | |
app: jira-postgres |
By now, we should have all prerequisites (dynamic PV and database) ready. Lets start to build Jira Data Center.
Jira Data Center needs two home folders: One is local home folder, the other one is shared home folder. They both need to be stored on persistent volume, as pods are short living, but the data needs to stay permanently.
Step one: create a persistent volume for the shared home. As we use dynamic persistent volume provisioning, we only need to create a PVC (persistent volume claim), the PV (persistent volume) will be created on the fly.
— | |
kind: PersistentVolumeClaim | |
apiVersion: v1 | |
metadata: | |
name: jira-share-pvc | |
labels: | |
app: jira-share | |
spec: | |
accessModes: | |
– ReadWriteMany | |
storageClassName: glusterfs | |
resources: | |
requests: | |
storage: 10Gi |
Step two: create a config map which will be used to pass the environment variables into the containers. Adjust the settings accordingly. In the example, we use the official Jira Software docker images
— | |
apiVersion: v1 | |
kind: ConfigMap | |
metadata: | |
name: jira-config | |
labels: | |
app: jira | |
data: | |
JVM_MINIMUM_MEMORY: 2048m | |
JVM_MAXIMUM_MEMORY: 2048m | |
ATL_PROXY_NAME: jira-sandbox.mydomain.com | |
ATL_PROXY_PORT: '32631' |
Step three: create statefulSet for Jira. As Jira cluster is a stateful application, here statefulSet fits better than deployment. e.g statefulSet supports ordinal startup and shutdown. The jira local home folder is created dynamically here, and it is tied to a specific pod based on the pod’s name. e.g jira-0, jira-1 …
— | |
apiVersion: apps/v1 | |
kind: StatefulSet | |
metadata: | |
name: jira | |
spec: | |
serviceName: jira | |
replicas: 3 | |
selector: | |
matchLabels: | |
app: jira | |
template: | |
metadata: | |
labels: | |
app: jira | |
spec: | |
containers: | |
– name: jira | |
image: atlassian/jira-software:8.5 | |
readinessProbe: | |
httpGet: | |
path: /status | |
port: 8080 | |
initialDelaySeconds: 120 | |
periodSeconds: 10 | |
livenessProbe: | |
httpGet: | |
path: / | |
port: 8080 | |
initialDelaySeconds: 600 | |
periodSeconds: 10 | |
envFrom: | |
– configMapRef: | |
name: jira-config | |
ports: | |
– containerPort: 8080 | |
name: web | |
volumeMounts: | |
– name: local-home | |
mountPath: /var/atlassian/application-data/jira | |
– name: jira-share-pv | |
mountPath: /var/atlassian/application-data/jira/shared-home | |
volumes: | |
– name: jira-share-pv | |
persistentVolumeClaim: | |
claimName: jira-share-pvc | |
volumeClaimTemplates: | |
– metadata: | |
name: local-home | |
spec: | |
accessModes: [ "ReadWriteOnce" ] | |
resources: | |
requests: | |
storage: 5Gi |
Step four: create a service for Jira. You can either do NodePort or ClusterIP. If you have ingress controller, then ClusterIP should just be fine. In my case, I use traefik to route the traffics to Jira service if the hostname is jira-sande.mydomain.com.
— | |
apiVersion: v1 | |
kind: Service | |
metadata: | |
name: jira | |
labels: | |
app: jira | |
spec: | |
type: NodePort | |
ports: | |
– port: 8080 | |
targetPort: 8080 | |
selector: | |
app: jira |
80% of the work should be done by now. The rest are just some configurations which I will show you in the part 2.
2 thoughts on “Run Jira Data Center on Kubernetes Part One”