# Deploy YouTrack with Kubernetes

This guide provides instructions that you can follow to deploy YouTrack to a Kubernetes cluster.

> **Note: Helm Support**
> YouTrack's certified consulting partner [twenty20](https://en.twenty20.de/) has developed a well-documented Helm chart for the deployment of YouTrack in a Kubernetes cluster. If you want to use this chart to simplify the deployment and management of your YouTrack installation, [visit Artifact Hub](https://artifacthub.io/packages/helm/twenty20-helm-charts/youtrack/) for further details.

This information is intended for use by administrators who are currently working with Kubernetes to manage an application ecosystem or are interested in migrating their applications to the popular cloud-native container orchestration system.

The instructions provided here describe how to set up a YouTrack instance in a Docker container on a single-node Kubernetes cluster. Multi-node installations are not supported at this time, but we have plans to support them in the future.

> **Note: Compatibility**
> The instructions on this page are appropriate for Windows, Linux, and macOS operating systems.

## Prerequisites

Before you start to deploy YouTrack to your Kubernetes cluster, ensure that you have everything you need to get started.

1. First, you will need to pull an image of the latest YouTrack version from the [Docker YouTrack Repository](https://hub.docker.com/r/jetbrains/youtrack/) using `docker pull` command:

```CONSOLE
docker pull jetbrains/youtrack:<version>
```

Replace `<version>` with the complete version number and build. For a complete list of release versions, check [Docker Hub](https://hub.docker.com/r/jetbrains/youtrack/tags/).

2. You will need `kubectl`, a command-line tool that lets you run commands for the Kubernetes cluster. If you haven't already installed it, [follow these instructions](https://kubernetes.io/docs/tasks/tools/#kubectl).

You'll also want to make sure that the target environment for the installation meets or exceeds the minimum requirements for installing YouTrack. For details, see [Supported Environments](youtrack-supported-environments.html).

When installing software on a server, it's generally recommended to use a user account with administrative or superuser privileges. In Unix-like operating systems, this user is often referred to as "root." In Windows, it's typically an account with administrative rights. Be sure that the account you use to access the server has permission to create folders and files in this environment.

## Installation in a Local Environment

There are various tools that you can use to set up a local Kubernetes cluster and deploy an application inside your network. Here, we provide instructions for [Docker Desktop](https://www.docker.com/products/docker-desktop/), [kind](https://github.com/kubernetes-sigs/kind), and [minikube](https://minikube.sigs.k8s.io/docs/start/).

Each tool provides the same result, so feel free to follow the instructions for whichever tool you are most comfortable using.

Docker Desktop:

Docker Desktop lets you run a Kubernetes cluster without having to configure the cluster manually. If you are already using Docker Desktop, this is the easiest approach. Make sure that Kubernetes is enabled on your Docker Desktop:

1. After installing Docker Desktop, click the Docker icon in your menu bar and navigate to `Preferences > Kubernetes`.

2. Select the Enable Kubernetes checkbox.

3. Click Apply & Restart.

Docker Desktop will automatically set up Kubernetes for you. To confirm that Kubernetes has been enabled successfully, check for a green light next to the label for Kubernetes.

kind:

[kind](https://github.com/kubernetes-sigs/kind) is a tool for running local Kubernetes clusters using Docker container “nodes”. It was primarily designed for testing Kubernetes itself, but may be used for local development or CI.

kind starts the Kubernetes cluster with one node inside the virtual machine locally.

1. Install [kind](https://kind.sigs.k8s.io/docs/user/quick-start/).

2. Use the following command to run kind and create a cluster:

```CONSOLE
kind create cluster
```

You should see the following information posted in the console output:

```CONSOLE
Creating cluster "kind" ...
✓ Ensuring node image (kindest/node:v1.25.0) 🖼
✓ Preparing nodes 📦
✓ Writing configuration 📜
✓ Starting control-plane 🕹️
✓ Installing CNI 🔌
✓ Installing StorageClass 💾
Set kubectl context to "kind-kind"
You can now use your cluster with:
kubectl cluster-info --context kind-kind
```

minikube:

You can start a Kubernetes cluster locally with minikube, another tool designed to work with Kubernetes in a local environment.

* Install [minikube](https://minikube.sigs.k8s.io/docs/start/).

* Use the following command to run minikube and create a cluster: ```CONSOLE minikube start ```

You should see the following information posted in the console output:

```CONSOLE
Starting local Kubernetes cluster...
Running pre-create checks...
Creating machine...
Starting local Kubernetes cluster...
```

## Describing Apps with Kubernetes YAML

All Kubernetes objects should be described in manifests called Kubernetes YAML files. To run and manage the YouTrack application, you need to create a youtrack-config.yaml file.

```YAML
apiVersion: v1
kind: Deployment
metadata:
    name: youtrack-deployment
    namespace: default
    labels:
        app: youtrack
spec:
    replicas: 1
        strategy:
            type: Recreate
    selector:
        matchLabels:
            app: youtrack
            bb: web
    template:
        metadata:
        labels:
            app: youtrack
    spec:
        containers:
        - name: youtrack
            image: jetbrains/youtrack:[youtrack-version].
---
apiVersion: v1
kind: Service
metadata:
    name: youtrack-entrypoint
    namespace: default
spec:
    type: NodePort
    ports:
    - port: [port]
        targetPort: [port]
        nodePort: [nodePort]
```

The `Deployment` section describes a scalable group of identical pods.

* The `replicas` configuration denotes that there is only one copy of your pod.

* The pod itself is described in the `template`.

* The `containers` section has just one container that is based on your `jetbrains/youtrack:[youtrack-version]` Docker image.

The second part of the file defines a `NodePort` service that routes traffic from a `[nodePort]` on your host to a `[port]` port inside the pods it routes to. This gives you the ability to access the YouTrack application from the network.

### Traffic Routing

Alternatively, you can replace the `NodePort` traffic routing service using `Ingress`. [Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) provides a more reliable solution aimed at constant service availability. With this approach, each service is assigned its own IP address. This lets you route traffic to backend services based on their paths and subdomains.

```YAML
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
    name: youtrack-ingress
    annotations:
        kubernetes.io/ingress.class: "nginx"
        nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
spec:
    rules:
    - host: myyoutrackdomain.com
        http:
            paths:
                - path: /youtrack/?(.*)
                pathType: Prefix
                backend:
                    service:
                        name: youtrack-entrypoint
                        port:
                            number: [port]
```

Be sure to check [which annotations](https://kubernetes.io/docs/concepts/services-networking/ingress/) you need to specify in the metadata section. Annotations are used to configure some options which depend on your Ingress controller. Pay attention to the correct path specification for your particular case as well. For more detailed differences in various approaches, please refer to the [Kubernetes documentation](https://kubernetes.io/docs/concepts/services-networking/ingress/).

### Provide Persistent Volumes to the Application

Files under the directories provided in this section are persisted. You may lose data from other directories on reboots. For this step, administrator access rights are required. Persistent volumes provisioning can be done in two ways:

Static
: Persistent volumes are configured to carry the details of the real storage, which is available for use by cluster users.

Dynamic
: The cluster dynamically creates a volume especially for each persistent volume claim.

Without dynamic provisioning, you have to manually make calls to the cloud or storage provider to create new storage volumes, and then create `PersistentVolume` objects to represent them in Kubernetes. Dynamic provisioning automatically provisions storage when it is requested by users.

As dynamic provisioning is considered to be the best practice we recommend using it. For more information, please refer to the [Kubernetes documentation](https://kubernetes.io/docs/concepts/storage/persistent-volumes).

### Dynamic Storage Provisioning

To enable dynamic provisioning, you need to pre-create one or more `StorageClass` objects for users. The name of a `StorageClass` object must be a valid DNS subdomain name.

```YAML
apiVersion: v1
kind: StorageClass
metadata:
    name: youtrack-storage-class
provisioner: kubernetes.io/gce-pd
parameters:
    type: pd-ssd
```

Include a storage class in the `PersistentVolumeClaim`:

```YAML
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
    name: youtrack-data-pv-claim
    namespace: default
spec:
    accessModes:
    - ReadWriteOnce
    storageClassName: storage-class-1
    resources:
        requests:
            storage: 1Gi
```

This claim results in the automatic provisioning of an SSD-like Persistent Disk. When the claim is deleted, the volume is destroyed.

You should create four persistent volume claims (PVCs) for each of the directories YouTrack uses to store application files: `data`, `conf`, `backups`, and `logs`.

> **Warning:**
> If there are already persistent volumes (PVs) that can be used for the PVCs, PVC classname should match the PV classname, otherwise this PV cannot be allocated for this PVC.

Dynamic provisioning can enable all claims to be dynamically provisioned if no storage class is specified. To do that, the following is required:

1. Designate one `StorageClass` object as the default by adding the `storageclass.kubernetes.io/is-default-class` annotation to it.

2. Make sure that the `DefaultStorageClass` admission controller is enabled on the API server.

> **Warning:**
> You can only designate one default storage class per cluster.

To learn more, refer to the [Kubernetes documentation](https://kubernetes.io/docs/concepts/storage/dynamic-provisioning/).

Pods access storage by using the claim as a volume. Claims must exist in the same namespace as the pod using the claim. The cluster gets the PV from the PVC, which is mounted to the host and into the pod. You can add volumes to the deployment configuration in the youtrack-config.yaml file:

```YAML
apiVersion: v1
kind: Deployment
metadata:
    name: youtrack-deployment
    namespace: default
    labels:
        app: youtrack
spec:
    replicas: 1
    selector:
        matchLabels:
            app: youtrack
            bb: web
    template:
        metadata:
            labels:
                app: youtrack
        spec:
            containers:
            - name: youtrack
                image: jetbrains/youtrack:[youtrack-version]
            volumeMounts:
            - name: opt-youtrack-data
                mountPath: /opt/youtrack/data
            - name: opt-youtrack-conf
                mountPath: /opt/youtrack/conf
            - name: opt-youtrack-logs
                mountPath: /opt/youtrack/logs
            - name: opt-youtrack-backups
                mountPath: /opt/youtrack/backups

            volumes:
            - name: opt-youtrack-data
                persistentVolumeClaim:
                    claimName:youtrack-data-pv-claim
            - name: opt-youtrack-conf
                persistentVolumeClaim:
                    claimName:youtrack-conf-pv-claim
            - name: opt-youtrack-logs
                persistentVolumeClaim:
                    claimName:youtrack-logs-pv-claim
            - name: opt-youtrack-backups
                persistentVolumeClaim:
                    claimName: youtrack-backups-pv-claim
```

## Deploy and Check Your Application

In a command-line interface, navigate to the folder where you created the `youtrack-config.yaml` file and deploy your application to Kubernetes:

```CONSOLE
$ kubectl apply -f youtrack-config.yaml
```

If the Kubernetes objects were created successfully, the following information is posted to the console:

```CONSOLE
deployment.apps/youtrack-deployment created
service/youtrack-entrypoint created
```

USe the following command to list all the deployments and verify that the pods described in the YAML file are up and running:

```CONSOLE
$ kubectl get deployments
```

Use the following command to verify that the services are running as well:

```CONSOLE
$ kubectl get services
```

## Installation in a Managed Kubernetes Service

Managed Kubernetes services are used to run, deploy, and operate Kubernetes clusters. Popular services include the [Amazon Elastic Kubernetes Service](https://aws.amazon.com/eks/), [Microsoft Azure Kubernetes Service](https://azure.microsoft.com/en-us/products/kubernetes-service/#overview), [Oracle Container Engine for Kubernetes](https://www.oracle.com/cloud/cloud-native/container-engine-kubernetes/), and [Google Kubernetes Engine](https://cloud.google.com/kubernetes-engine).

When working with a managed Kubernetes service, you need to make sure your worker nodes are using supported container runtimes. If you have node customizations, you may need to update them based on your environment and runtime requirements.

### Google Kubernetes Engine

Use this setup to run a YouTrack container image on a Google Kubernetes Engine (GKE) cluster.

#### Preparatory work

1. To run commands, you need to activate the Google Cloud Shell. Click the Activate Cloud Shell icon in the application header of the [Google Cloud Console](https://console.cloud.google.com/).

2. Select or create a Google Cloud project. If you experience any troubles during this stage, please refer to the [Google Cloud documentation](https://cloud.google.com/resource-manager/docs/creating-managing-projects).

* Use the following command to create a project in Google Cloud: ```CONSOLE gcloud projects create PROJECT_ID ```

* Use the following command to select an existing project: ```CONSOLE gcloud config set PROJECT_ID ```

3. Make sure that billing is enabled for your Cloud project. To learn how, please refer to the  [Google Cloud documentation](https://cloud.google.com/billing/docs/how-to/verify-billing-enabled).

4. Use the following command to enable the Artifact Registry and Google Kubernetes Engine API:

```CONSOLE
gcloud services enable artifactregistry.googleapis.com container.googleapis.com
```

5. First, you will need to pull an image of the latest YouTrack version from the [Docker YouTrack Repository](https://hub.docker.com/r/jetbrains/youtrack/) using `docker pull` command:

```CONSOLE
docker pull jetbrains/youtrack:<version>
```

Replace `<version>` with the complete version number and build. For a complete list of release versions, check [Docker Hub](https://hub.docker.com/r/jetbrains/youtrack/tags/).

6. Run the `docker images` command to verify that the build was successful:

```CONSOLE
docker images
```

In the output you should see jetbrains/youtrack:{version} among your loaded images:

```CONSOLE
REPOSITORY                TAG       IMAGE ID       CREATED      SIZE
jetbrains/youtrack   2022.1.42540   82c55a0fdf90   2 days ago   719MB
```

#### Deploy the YouTrack Image to the Cluster

1. Create a Kubernetes cluster or select a cluster that was created previously.

2. Use the following command to verify that you are connected to your GKE cluster.

```CONSOLE
gcloud container clusters get-credentials [cluster-name] --zone [zone]
```

3. Create a Kubernetes Deployment so you can run the YouTrack application on the cluster.

```CONSOLE
kubectl create deployment youtrack-app --image=jetbrains/youtrack:{version}
```

4. Create a `StorageClass` configuration in a `youtrack-storage-class.yaml` file:

```YAML
apiVersion: v1
kind: StorageClass
metadata:
    name: youtrack-storage-class
provisioner: kubernetes.io/gce-pd
parameters:
    type: pd-ssd
```

Apply the configuration:

```CONSOLE
kubectl apply -f youtrack-storage-class.yaml
```

5. Create persistent volume claim (PVC) configurations for the `data`, `config`, `logs` and `backup` directories:

For example, use the following command to create the data PVC configuration file:

```CONSOLE
nano pvc-data.yaml
```

Then add this content to the file:

```YAML
—-----
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
    name: youtrack-data-pv-claim
    namespace: default
spec:
    accessModes:
        - ReadWriteOnce
    storageClassName: storage-class-1
    resources:
        requests:
            storage: 1Gi
```

Use the following command to apply the configuration:

```CONSOLE
kubectl apply -f pvc-data.yaml
```

6. New PVs are generated based on the newly created PVCs. To verify their creation, check `Storage > [select desired PVC] > Volume`.

7. You need to attach the PV to the Deployment. To perform this step, navigate to `Workloads > [select deployment] > YAML > Edit` and insert the following:

```YAML
volumeMounts:
- mountPath: /opt/youtrack/data
name: [data volume name]
- mountPath: /opt/youtrack/conf
name: [conf volume name]
- mountPath: /opt/youtrack/logs
name: [logs volume name]
- mountPath: /opt/youtrack/backups
name: [backup volume name]
                            …
volumes:
- name: [data volume name]
persistentVolumeClaim:
    claimName: youtrack-data-pv-claim
- name: [logs volume name]
persistentVolumeClaim:
    claimName: youtrack-logs-pv-claim
- name: [backups volume name]
persistentVolumeClaim:
    claimName: youtrack-backups-pv-claim
- name: [conf volume name]
persistentVolumeClaim:
    claimName: youtrack-conf-pv-claim
```

You should now see corresponding volumes in the Pod specification in your Deployment.

#### Exposing the Application

Due to the specific nature of the Google Cloud service, the set of IP addresses that correspond to the active set of Pods is dynamic. You can expose a group of Pods outside the Kubernetes cluster with [Services](https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer) . This feature groups Pods into one static IP address, which can be reached from any Pod inside the cluster. The static IP address also is assigned a DNS hostname, for example, youtrack-app.default.svc.cluster.local.

```CONSOLE
kubectl expose deployment youtrack-app --name=test-service --type=LoadBalancer --port 80 --target-port 8080
```

To get more details about the service run:

```CONSOLE
kubectl get service
```

You should receive an output like this:

```CONSOLE
NAME              CLUSTER-IP    EXTERNAL-IP     PORT(S)          AGE
                    hello-app-service  10.3.251.122    213.1.234.0  80:30878/TCP     11s
```

After that, you can open a new browser tab and navigate to the `EXTERNAL-IP:PORT`, where `PORT` is equal to the `target-port` that you defined in the `kubectl expose` command. There you will see a Setup Wizard that lets you continue installing the YouTrack application.

#### Troubleshooting

If you encounter problems with the installation, see if any of the following conditions apply.

Condition — You encounter a `CrashLoopBackOff` error.

| Cause | Solution |
| --- | --- |
| The pod may be crashing because it starts up and exits immediately afterward, then Kubernetes restarts and the cycle continues. For more details please check the [Pod Lifecycle documentation](https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle/). | Add a command like `sleep` to the `volumeMounts` section of the YAML file to keep the container alive.      ```YAML volumeMounts:     - mountPath: /opt/youtrack/conf     name: [conf volume name]     … command: ["/bin/sh"]      # add command args: ["-c", "sleep 60"]  # sleep command for 60 seconds ```   |

Condition — The error directory opt/youtrack/data is not writable.

| Cause | Solution |
| --- | --- |
| The directory doesn't exist or you don't have sufficient permissions. |      1. Check if the directory exists.    2. Use the following command to set the permissions for the directory:      ```CONSOLE chown -R 13001:13001 [directory name] ```      |

