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
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:
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/
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:
Top comments (0)