Running Atlassian Bitbucket Server on Kubernetes
Tags: docker, kubernetes, git, bitbucket
Published: 2018-12-10 01:32:09

---
title: Running Atlassian Bitbucket Server on Kubernetes
published: true
tags: docker,kubernetes,git,bitbucket
canonical_url: https://medium.com/@jmarhee/running-atlassian-bitbucket-server-on-kubernetes-e3f13779ae36
---

Atlassian provides a Docker image for their Bitbucket Server product, which makes running this product exceptionally simple, however, I wanted to create a durable, scalable version of this to run on my Kubernetes cluster. I did this using a standard Deployment resource for the server, and ran Postgres using a PersistentVolume to store the server data.

#### **Creating the Bitbucket Deployment and Service**

We’ll start by defining our Bitbucket deployment’s PersistentVolume for the application data:

```
kind: PersistentVolume
apiVersion: v1
metadata:
  name: bitbucket-pv-volume
  labels:
    type: local
    app: bitbucket
spec:
  storageClassName: manual
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteMany
  hostPath:
    path: "/mnt/kube-data/bitbucket"
    type: Directory
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: bitbucket-pv-claim
  labels:
    app: bitbucket
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
```

and then we’ll use this PersistentVolumeClaim on our Deployment:

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: bitbucket-deployment
  labels:
    app: bitbucket
spec:
  replicas: 1
  selector:
    matchLabels:
      app: bitbucket
  template:
    metadata:
      labels:
        app: bitbucket
    spec:
      containers:
      - name: bitbucket
        image: atlassian/bitbucket-server
        ports:
        - containerPort: 7990
          name: bitbucket-http
        - containerPort: 22
          name: bitbucket-ssh
        volumeMounts:
        - mountPath: /var/atlassian/application-data/bitbucket
          name: bitbucket-data
        env:
        - name: SERVER\_SECURE
          value: "true"
        - name: SERVER\_SCHEME
          value: "https"
        - name: SERVER\_PROXY\_PORT
          value: "443"
        - name: SERVER\_PROXY\_NAME
          value: ""
      volumes:
        - name: bitbucket-data
          persistentVolumeClaim:
            claimName: bitbucket-pv-claim
```

Our deployment is using the env key to set some variables to enable HTTPS support for this application, so if you wish to do this as well, you can set your FQDN in SERVER\_PROXY\_NAME . You’ll also notice we’re using the PersistentVolume we created in this Deployment, so you’ll be re-attaching this volume to the pods for this deployment on subsequent recreates (rather than a bare hostPath, which is slightly less durable in this instance).

The last thing to do will be to create a Service to expose the Server UI to the web:

```
kind: Service
apiVersion: v1
metadata:
  name: bitbucket-service
spec:
  selector:
    app: bitbucket
  ports:
  - name: bitbucket-http
    port: 7990
    targetPort: bitbucket-http
  - name: bitbucket-ssh
    port: 2222
    targetPort: bitbucket-ssh
  type: LoadBalancer
```

This will allow you to push and pull via HTTP or SSH once the server installation is completed.

**Note:** T_he setup takes place in the UI, outside the scope of this tutorial, so hang onto the following link for after you’ve completed this guide to complete the setup:_

[https://confluence.atlassian.com/bitbucketserver/install-a-bitbucket-server-trial-867192384.html](https://confluence.atlassian.com/bitbucketserver/install-a-bitbucket-server-trial-867192384.html)

#### Creating the Postgres Deployment and Service

The first thing you need to do is store your credentials for Postgres in a Secret :

```
apiVersion: v1
kind: Secret
metadata:
  name: bitbucket-postgres
type: Opaque
data:
  username: <base64-encoded string>
  password: <base64-encoded string>
  postgres\_db: bitbucket
```

I prefer to use SealedSecret resources, that way I can check all of these resources into version control, but a standard Secret will suffice:

[bitnami-labs/sealed-secrets](https://github.com/bitnami-labs/sealed-secrets)

You will also need a new PersistentVolume , again I’ll use the same method:

```
kind: PersistentVolume
apiVersion: v1
metadata:
  name: postgres-pv-volume
  labels:
    type: local
    app: postgres
spec:
  storageClassName: manual
  capacity:
    storage: 5Gi
  accessModes:
    - ReadWriteMany
  hostPath:
    path: "/mnt/kube-data/postgres"
    type: Directory
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
  name: postgres-pv-claim
  labels:
    app: postgres
spec:
  storageClassName: manual
  accessModes:
    - ReadWriteMany
  resources:
    requests:
      storage: 5Gi
```

then we’ll create the Deployment, which you’ll see we are importing the Secret data, decoded, into environmental variables into the Pod:

```
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: postgres
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: postgres
    spec:
      containers:
        - name: postgres
          image: postgres:10.4
          imagePullPolicy: "IfNotPresent"
          ports:
            - containerPort: 5432
          env:
          - name: POSTGRES\_DB
            valueFrom:
              secretKeyRef:
                name: bitbucket-postgres
                key: dbname
          - name: POSTGRES\_ADMIN
            valueFrom:
              secretKeyRef:
                name: bitbucket-postgres
                key: username
          - name: POSTGRES\_PW
            valueFrom:
              secretKeyRef:
                name: bitbucket-postgres
                key: password
          volumeMounts:
            - mountPath: /var/lib/postgresql/data
              name: postgredb
      volumes:
        - name: postgredb
          persistentVolumeClaim:
            claimName: postgres-pv-claim
```

This will run in a single instance (with the data backed by a volume for some durability), and I don’t recommend this for production use, but for your Bitbucket Server trial (or for a low-tenency instance), it should suffice. You can upgrade this to a StatefulSet to make the Postgres infrastructure more robust/reliable:

[https://kubernetes.io/blog/2017/02/postgresql-clusters-kubernetes-statefulsets/](https://kubernetes.io/blog/2017/02/postgresql-clusters-kubernetes-statefulsets/)

Once all of this is deployed, make note of your Postgres credentials. The last piece, in order to have the Bitbucket Server application to access the Postgres endpoint, is a Service definition:

```
apiVersion: v1
kind: Service
metadata:
  name: postgres-service
spec:
  selector:
    app: postgres
  ports:
  - protocol: TCP
    port: 5432
    targetPort: 5432
```

This will allow connections to port 5432 to the postgres-deployment pods using the hostname on internal DNS:

```
postgres-service.default.svc.cluster.local
```

which you’ll use when you proceed to your LoadBalancer address for the Bitbucket Server UI to complete the setup.

#### Post Setup

On the Docker container documentation, Atlassian notes that, to avoid issues with backwards compatibility between version, you should pin your Deployment to a specific release tag, rather than latest . I deployed using latest to ensure the most recent release, but once I’ve done that, I can pull the current ID, using:

```
kubectl describe pod -l app=bitbucket-server
```

and in the response, you’ll see a field like:

```
$ kubectl describe pod bitbucket-deployment-54f9cbff55-cmjrs
Name: bitbucket-deployment-54f9cbff55-cmjrs
Namespace: default
Priority: 0
PriorityClassName: <none>
Node: <node ID>/<node IP>
Start Time: Wed, 28 Nov 2018 18:02:50 +0000
Labels: app=bitbucket
                    pod-template-hash=54f9cbff55
Annotations: <none>
Status: Running
IP:
Controlled By: ReplicaSet/bitbucket-deployment-54f9cbff55
Containers:
  bitbucket:
    Container ID: docker://af14c60d72a8301c37be73a9864c6a96cc6171a4741b0504b620d003938717ff
    Image: atlassian/bitbucket-server
    Image ID: docker-pullable://atlassian/bitbucket-server@sha256:061d88d1116c3b99cb8dba592631cde947c7d1719cccdd08180dabb020da44f8
```

You’ll want to grab the ImageID field value:

```
atlassian/bitbucket-server@sha256:061d88d1116c3b99cb8dba592631cde947c7d1719cccdd08180dabb020da44f8
```

and apply it to your deployment:

```
kubectl set image deployment/bitbucket-deployment bitbucket=atlassian/bitbucket-server@sha256:061d88d1116c3b99cb8dba592631cde947c7d1719cccdd08180dabb020da44f8
```

in order to prevent a pod recycle event from pulling latest once tagged to a different release, and ceasing to work with your existing installation down the road.

Once you’ve completed all these steps, you can proceed to the UI at your load balancer address (or hostname, if you enabled HTTPS), and complete the installation:

[Install a Bitbucket Server trial - Atlassian Documentation](https://confluence.atlassian.com/bitbucketserver/install-a-bitbucket-server-trial-867192384.html)