Hands-On GitOps With OneDev and Kubernetes
GitOps is a DevOps approach to maintain and operate Kubernetes-based infrastructure as code in git. OneDev is an open-source git repository server with built-in CI/CD integration. This tutorial explains how to set up OneDev to do GitOps in Kubernetes.
Join the DZone community and get the full member experience.
Join For FreeSet Up Kubernetes Cluster
First, we need a Kubernetes cluster. You may use an existing one or set up a new one. For this tutorial, we chose to use GKE (Google Kubernetes Engine).
Just follow the quick start to create a cluster. To save your money, the default pool with only one node is sufficient for our testing. For node image type, use the default Container-Optimized OS; for machine type, please select one with at least 8G mem. After creating the cluster, go ahead to configure kubectl to connect to the cluster following this guide.
To verify that things are working, run below command in your terminal to make sure it is successful:
xxxxxxxxxx
$ kubectl cluster-info
Install OneDev Into Kubernetes Cluster
Now that we have a working cluster, let’s deploy OneDev into the cluster to manage code of our demo project
- Download OneDev k8s resources, extract it, and run the below commands to deploy OneDev. Note that OneDev by default will apply two persistent volumes to store data. one is of 100G to store git repositories, and another is of 10G to store database files. This setting can be adjusted via file k8s-resources/production/disk-settings.yaml if desired.
Shell
xxxxxxxxxx
1
1$ cd k8s-resources/production
2$ kubectl apply -k .
- After deployment, run the below command to show external IP of the OneDev service (you may need to wait a while for the external IP to be assigned):
Shell
xxxxxxxxxx
1
1$ kubectl get services -n onedev
- Open the URL http:// with your browser to set up OneDev. Wait a while and try again if OneDev is not ready.
Add a Demo Project Into OneDev
OneDev should be up and running. Let’s set up a demo project now:
- From OneDev projects page, add a project named gitops-demo.
- From the terminal, create a React project, and push to OneDev by running the below commands. Note that you need to have a node.js environment. Refer to the React documentationif you are not familiar with it.
Shell
xxxxxxxxxx
1
1$ npx create-react-app gitops-demo
2$ cd gitops-demo
3$ git remote add origin http:///gitops-demo
4$ git push --set-upstream origin master
5(use OneDev admin account created previously for authentication)
- Refresh files page of the demo project in OneDev, and click the “add build spec” link as below:
- From the build spec edit page, switch to the Edit Source tab without adding any job and replace the source with below content. Don’t worry about the syntax. In most cases, you only need to work with the GUI editor.
Plain Text
xxxxxxxxxx
129
1version: 1
2jobs:
3- name: CI
4image: node:10.16-alpine
5commands:
6- set -e
7- ''
8- apk add --update jq
9- buildVersion=`jq -r '.version' package.json`
10- echo "##onedev[SetBuildVersion '$buildVersion']"
11- ''
12- npm install -g yarn
13- yarn install
14- ''
15- export CI=true
16- yarn test
17triggers:
18- !BranchUpdateTrigger {}
19retrieveSource: true
20cloneCredential: !DefaultCredential {}
21cpuRequirement: 250m
22memoryRequirement: 128m
23retryCondition: never
24maxRetries: 3
25retryDelay: 30
26caches:
27- key: npm-cache
28path: /root/.npm
29timeout: 3600
Save and commit the change. Our CI build should be running now as demonstrated below:
Set Up GitOps for the Demo Project
We now have a demo project with CI ability. Let’s improve it to be able to deploy to Kubernetes:
- To deploy to Kubernetes, we need to build and publish Docker image of the demo project. We will use the official Docker hub registry here. Please visit https://hub.docker.com, login with your account, and create a public repository, say gitops-demo (OneDev also works with private repositories; we created a public repository here for simplicity).
To be able to publish a Docker image to your repository, OneDev needs to know credential of your Docker hub account. To do it, add a job secret in the demo project, give it a name, (for instance, dockerhub-password), and input the Docker hub password as a value of the secret.
- To deploy Docker image of the demo project into Kubernetes, we need to give extra permissions to OneDev builds. To do this, create a file, say gitops-demo-role.yaml, in your terminal with the below content:
Plain Text
xxxxxxxxxx
111
1kind: ClusterRole
2apiVersion: rbac.authorization.k8s.io/v1
3metadata:
4name: gitops-demo
5rules:
6- apiGroups: [""]
7resources: ["services"]
8verbs: ["get", "create"]
9- apiGroups: ["apps"]
10resources: ["deployments"]
11verbs: ["get", "patch", "create"]
Shell
xxxxxxxxxx
1
1$ kubectl apply -f gitops-demo-role.yaml
- Since we need to build a Docker image of our demo project, let’s add a Dockerfile in root of the project with below content:
Dockerfile
xxxxxxxxxx
1
1FROM nginx:1.19.5
2COPY build /usr/share/nginx/html
3EXPOSE 80
- We deploy the demo project via Kubernetes resources, so continue to add a file k8s.yaml in root of the project with below content and replace all occurrences of with name of your Docker hub account:
Plain Text
xxxxxxxxxx
139
1apiVersion: apps/v1
2kind: Deployment
3metadata:
4name: gitops-demo
5labels:
6tier: gitops-demo
7spec:
8selector:
9matchLabels:
10tier: gitops-demo
11strategy:
12type: Recreate
13template:
14metadata:
15name: gitops-demo
16labels:
17tier: gitops-demo
18spec:
19containers:
20- name: gitops-demo
21image: /gitops-demo:imageTag
22ports:
23- containerPort: 80
24---
25apiVersion: v1
26kind: Service
27metadata:
28name: gitops-demo
29labels:
30tier: gitops-demo
31spec:
32type: LoadBalancer
33ports:
34- name: http
35port: 80
36targetPort: 80
37protocol: TCP
38selector:
39tier: gitops-demo
- Edit build spec in OneDev (click the file .onedev-buildspec.yaml from the root of the project and then edit it), replace property image with docker:19.03.5, replace property commandswith the below content, and replace all occurrences of with name of your Docker hub account.
Shell
xxxxxxxxxx
116
1set -e
2apk add --update npm jq curl
3buildVersion=`jq -r '.version' package.json`
4echo "##onedev[SetBuildVersion '$buildVersion']"
5npm install -g yarn
6yarn install
7export CI=true
8yarn test
9yarn build
10docker build -t /gitops-demo:@commit_hash@ .
11docker login -u -p @secrets:dockerhub-password@
12docker push /gitops-demo:@commit_hash@
13curl -o /usr/local/bin/kubectl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl"
14chmod +x /usr/local/bin/kubectl
15sed -i "s/imageTag/@commit_hash@/g" k8s.yaml
16kubectl apply -f k8s.yaml -n default
- Save and commit the change. OneDev will start to build and deploy the demo project. After build is successful, run the below command to show the external IP address of the published demo service:
Shell
xxxxxxxxxx
1
1$ kubectl get service gitops-demo
Open the URL http:// with your browser to show the deployed demo app. - Congrats! You’ve successfully set up GitOps for the demo project. Whenever there is a new commit pushed to master branch, the CI job will be triggered to test, build, and redeploy the project. If you want to revert to the previous deployment, just run
git revert master
and push the change.
Multiple Deployment Environments
In our setup above, we deploy the demo project directly into the default namespace, which is not good. In real world, we may need to create multiple namespaces to cater deployment of multiple environments. Let’s create two namespaces, one for test and one for production:
xxxxxxxxxx
$ kubectl create namespace test
$ kubectl create namespace production
This tells OneDev to deploy our demo project into production namespace if built against the master branch and deploy into the namespace identified by branch name otherwise. After committing the change, OneDev should be deploying the demo project into production namespace.
Now let’s create the test branch to track deployments for the test environment. After creating the branch, OneDev will start to deploy the demo project into test namespace.
To get Kubernetes printing external ip address of deployed demo service in specified namespaces, run below command:
xxxxxxxxxx
kubectl get service -n <namespace>
Now, from the commits page, we have a clear view of deployment status in different environments and we can control deployments in different environments by pushing/merging into corresponding branches.
Thanks for reading!
Opinions expressed by DZone contributors are their own.
Comments