GitOps

0 Goal

In this tutorial, we will try to use DevStream to achieve the following:

  1. create a new repository for a Python web application written with Flask;
  2. setup basic CI pipelines for the repo we created with GitHub Actions;
  3. install Argo CD for GitOps in an existing Kubernetes cluster;
  4. create an Argo CD application that deploys the web application generated in step 1.

Note:

in step 3, Argo CD is installed in an existing Kubernetes cluster. Setting up infrastructure like a Kubernetes cluster is something DevStream chooses not to do.

If you want to follow this tutorial and give it a try yourself but don’t know how to get a Kubernetes cluster up and running locally, maybe the following blogs (also from DevStream) would help:


1 TL;DR: See It in Action

If you prefer to see this GitOps doc in action, check out the video demo below:

It’s from an older version of DevStream with slightly different configuration files, but you get the gist. We will update the video with the latest version of DevStream soon; bear with us for a little while.

For Chinese readers, watch this one:

However, if you are like us, who prefer to do things hands-on and get their hands dirty, read on, follow the steps, and have a go yourself!


2 Overview

DevStream will use the following plugins to achieve the goal described in Section 0:

  1. repo-scaffolding
  2. github-actions
  3. helm-installer
  4. argocdapp

However, you do not have to worry about these plugins because DevStream will manage them automatically for you.


3 Getting Started: Download DevStream (dtm)

Create a temporary working directory for this tutorial:

Bash

  1. mkdir test
  2. cd test/

Then, under the newly created directory, execute the following command:

Bash

  1. sh -c "$(curl -fsSL https://download.devstream.io/download.sh)"

This script checks your system and downloads the corresponding dtm binary. Then the binary will be granted execution permission.

If you do an ls, you can see the binary dtm has been downloaded:

Bash

  1. tiexin@mbp ~/work/devstream-io/test $ ls
  2. dtm

And as a test, try to execute it, and you will get similar output to the following:

Bash

  1. tiexin@mbp ~/work/devstream-io/test $ ./dtm
  2. DevStream is an open-source DevOps toolchain manager
  3. ###### #####
  4. # # ###### # # # # ##### ##### ###### ## # #
  5. # # # # # # # # # # # # ## ##
  6. # # ##### # # ##### # # # ##### # # # ## #
  7. # # # # # # # ##### # ###### # #
  8. # # # # # # # # # # # # # # #
  9. ###### ###### ## ##### # # # ###### # # # #
  10. Usage:
  11. dtm [command]
  12. Available Commands:
  13. apply Create or update DevOps tools according to DevStream configuration file
  14. completion Generate the autocompletion script for dtm for the specified shell
  15. delete Delete DevOps tools according to DevStream configuration file
  16. destroy Destroy DevOps tools deployment according to DevStream configuration file & state file
  17. develop Develop is used for develop a new plugin
  18. help Help about any command
  19. init Download needed plugins according to the config file
  20. list This command only supports listing plugins now
  21. show Show is used to print plugins' configuration templates or status
  22. upgrade Upgrade dtm to the latest release version
  23. verify Verify DevOps tools according to DevStream config file and state
  24. version Print the version number of DevStream
  25. Flags:
  26. --debug debug level log
  27. -h, --help help for dtm
  28. Use "dtm [command] --help" for more information about a command.

Optional: you can move dtm to a directory which is in your $PATH. For example: mv dtm /usr/local/bin/. This will allow you to run dtm directly without having to prefix it with the dot and slash (./dtm).

For more methods on how to install DevStream, see install dtm.


4 Config File

Run command below to get a valid config.yaml file:

Bash

  1. ./dtm show config -t gitops > config.yaml

Then modify the vars section in the config.yaml file accordingly. Please update the values for githubUser and dockerUser to your real users.

In the example above, I set these vars like the following:

VariableExampleNote
githubUserIronCore864case-sensitive, use your GitHub username strictly here
dockerUserironcore864case-sensitive, use your DockerHub username strictly here

5 Environment Variables

The following environment variables are required for this to work:

Bash

  1. export GITHUB_TOKEN="YOUR_GITHUB_TOKEN_HERE"
  2. export IMAGE_REPO_PASSWORD="YOUR_DOCKERHUB_TOKEN_HERE"

Note:

if you don’t know how to create these two tokens, check out:


6 Init

Run:

Bash

  1. ./dtm init -f config.yaml

This downloads the required plugins, according to the config file, automatically.

You’ll get some outputs similar to the following:

Bash

  1. 2022-12-05 17:46:01 [INFO] Using dir </Users/tiexin/.devstream/plugins> to store plugins.
  2. 2022-12-05 17:46:01 [INFO] -------------------- [ repo-scaffolding-darwin-arm64_0.10.2 ] --------------------
  3. ... (omitted)
  4. ... (omitted)
  5. 2022-12-05 17:46:51 [SUCCESS] Initialize finished.

7 Apply

Run:

Bash

  1. ./dtm apply -f config.yaml -y

You will see similar outputs as the following:

Text Only

  1. 2022-12-05 17:49:49 [INFO] Apply started.
  2. 2022-12-05 17:49:49 [INFO] Using local backend. State file: devstream.state.
  3. 2022-12-05 17:49:49 [INFO] Tool (repo-scaffolding/myapp) found in config but doesn't exist in the state, will be created.
  4. 2022-12-05 17:49:49 ℹ [INFO] Tool (helm-installer/argocd) found in config but doesn't exist in the state, will be created.
  5. 2022-12-05 17:49:49 [INFO] Tool (github-actions/flask) found in config but doesn't exist in the state, will be created.
  6. 2022-12-05 17:49:49 ℹ [INFO] Tool (argocdapp/default) found in config but doesn't exist in the state, will be created.
  7. 2022-12-05 17:49:49 [INFO] Start executing the plan.
  8. 2022-12-05 17:49:49 [INFO] Changes count: 4.
  9. ... (omitted)
  10. ... (omitted)
  11. 2022-12-05 17:51:51 [INFO] -------------------- [ Processing progress: 4/4. ] --------------------
  12. 2022-12-05 17:51:51 [INFO] Processing: (argocdapp/default) -> Create ...
  13. 2022-12-05 17:51:52 [INFO] application.argoproj.io/helloworld created
  14. 2022-12-05 17:51:52 [SUCCESS] Tool (argocdapp/default) Create done.
  15. 2022-12-05 17:51:52 [INFO] -------------------- [ Processing done. ] --------------------
  16. 2022-12-05 17:51:52 [SUCCESS] All plugins applied successfully.
  17. 2022-12-05 17:51:52 [SUCCESS] Apply finished.

8 Check the Results

Let’s continue to look at the results of the apply command.

8.1 Repository

The repository is created automatically by DevStream with scaffolding code:

GitOps - 图1

8.2 CI Pipelines with GitHub Actions

GitHub Actions pipelines are created and executed:

GitOps - 图2

8.3 Argo CD Installation

Argo CD is installed in your Kubernetes cluster:

Bash

  1. tiexin@mbp ~/work/devstream-io/test $ kubectl get namespaces
  2. NAME STATUS AGE
  3. argocd Active 5m42s
  4. default Active 6m28s
  5. kube-node-lease Active 6m29s
  6. kube-public Active 6m29s
  7. kube-system Active 6m29s
  8. local-path-storage Active 6m25s
  9. tiexin@mbp ~/work/devstream-io/test $ kubectl get pods -n argocd
  10. NAME READY STATUS RESTARTS AGE
  11. argocd-application-controller-0 1/1 Running 0 5m43s
  12. argocd-applicationset-controller-66687659f-dsrtd 1/1 Running 0 5m43s
  13. argocd-dex-server-6944757486-clshl 1/1 Running 0 5m43s
  14. argocd-notifications-controller-7944945879-b9878 1/1 Running 0 5m43s
  15. argocd-redis-7887bbdbbb-xzppj 1/1 Running 0 5m43s
  16. argocd-repo-server-d4f5cc7cb-8gj24 1/1 Running 0 5m43s
  17. argocd-server-5bb75c4bd9-g948r 1/1 Running 0 5m43s

8.4 Continuous Deployment with Argo CD

The CI pipelines build a Docker image and push it into Dockerhub, and an Argo CD application created by DevStream deploys the app already:

Bash

  1. tiexin@mbp ~/work/devstream-io/test $ kubectl get deployment -n default
  2. NAME READY UP-TO-DATE AVAILABLE AGE
  3. helloworld 1/1 1 1 5m16s
  4. tiexin@mbp ~/work/devstream-io/test $ kubectl get pods -n default
  5. NAME READY STATUS RESTARTS AGE
  6. helloworld-69b5586b94-wjwd9 1/1 Running 0 5m18s
  7. tiexin@mbp ~/work/devstream-io/test $ kubectl get services -n default
  8. NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
  9. helloworld ClusterIP 10.96.73.97 <none> 80/TCP 5m27s
  10. kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 8m2s

If you do a port-forwarding:

Bash

  1. kubectl port-forward -n default svc/helloworld 8080:80

And accesses localhost:8080 in your browser, you can see the deployed app return a “Hello, World!” to you. Hooray!


9 Clean Up

Run:

Bash

  1. ./dtm delete -f config.yaml -y

And you will get similar outputs to the following:

Bash

  1. 2022-12-05 17:59:25 [INFO] Delete started.
  2. 2022-12-05 17:59:26 [INFO] Using local backend. State file: devstream.state.
  3. 2022-12-05 17:59:26 [INFO] Tool (argocdapp/default) will be deleted.
  4. 2022-12-05 17:59:26 [INFO] Tool (github-actions/flask) will be deleted.
  5. 2022-12-05 17:59:26 [INFO] Tool (repo-scaffolding/myapp) will be deleted.
  6. 2022-12-05 17:59:26 [INFO] Tool (helm-installer/argocd) will be deleted.
  7. 2022-12-05 17:59:26 [INFO] Start executing the plan.
  8. 2022-12-05 17:59:26 [INFO] Changes count: 4.
  9. ... (omitted)
  10. ... (omitted)
  11. 2022-12-05 17:59:35 [INFO] -------------------- [ Processing done. ] --------------------
  12. 2022-12-05 17:59:35 [SUCCESS] All plugins deleted successfully.
  13. 2022-12-05 17:59:35 [SUCCESS] Delete finished.

Then you can delete what we created:

Bash

  1. cd ../
  2. rm -rf test/
  3. rm -rf ~/.devstream/