Introduction

The below picture shows the GitOps workflow demonstrated in this story.

Install ArgoCD

$ kubectl create namespace argocd
$ kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

Check result:

Service Type Load Balancer

Change the argocd-server service type to LoadBalancer:

kubectl patch svc argocd-server -n argocd -p '{"spec": {"type": "LoadBalancer"}}

Port Forwarding

Kubectl port-forwarding can also be used to connect to the API server without exposing the service.

kubectl port-forward svc/argocd-server -n argocd  --address 0.0.0.0 8080:443

Access ArgoCD in browser:

Default username is admin, password is the name of the pod. Example:

[email protected]:~# kubectl get pods -n argocd -l app.kubernetes.io/name=argocd-server -o name | cut -d'/' -f 2
argocd-server-58d895fb8b-sbd6q

GitLab Project Setup

GitLab comes not only with CI/CD, but also provides container registry for each project. I want to use it in my example.

It is also necessary to create an Access Token with API scope. This will be used later in the pipeline for git commits. You can create your own in USER -> SETTINGS -> ACCESS TOKENS

Next, add necessary Environment Variables to the project ( Settings -> CI/CD -> Variables):

  • CI_PUSH_TOKEN — the token
  • CI_USERNAME — the username of the token owner

ArgoCD Application Setup

init_deploy_k8s_svc.yml

---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: demo-argocd-webapp-dev
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://<private-registry>/demo-argocd.git
    targetRevision: HEAD
    path: deployment/dev
  destination:
    server: https://kubernetes.default.svc
    namespace: dev
  syncPolicy:
    automated:
      prune: true
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: demo-argocd-webapp-prod
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://<private-registry>/demo-argocd.git
    targetRevision: HEAD
    path: deployment/prod
  destination:
    server: https://kubernetes.default.svc
    namespace: prod
  syncPolicy:
    automated:
      prune: true

GitLab CI/CD Pipeline

Dockerfile <private-registry>/argocli:1

FROM alpine:3.8
RUN apk add --no-cache git curl bash
RUN curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"  | bash
RUN mv kustomize /usr/local/bin/

ADD .gitconfig ~/.gitconfig
ADD argocd /usr/local/bin/argocd
RUN chmod +x /usr/local/bin/argocd

Get ArgoCD auth-token:

argocd proj role create default cicd
# Role 'cicd' created
argocd proj role create-token default cicd
# eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1ODg4MTgzMzgsImlzcyI6ImFyZ29jZCIsIm5iZiI6MTU4ODgxODMzOCwic3ViIjoicHJvajpkZWZhdWx0OmNpY2QifQ.KeabVLC7UYj6nwn5HzA95_EjsYNvXkaMAQVjLz4jMSU
# [email protected]:~# argocd proj role add-policy default cicd -a sync -o '*' -p 'allow'

Test auth-token sync ArgoCD app:
# argocd --server 10.0.1.70:31437 --insecure app sync demo-argocd-laravel-dev  --auth-token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpYXQiOjE1ODg3NTQzMTcsImlzcyI6ImFyZ29jZCIsIm5iZiI6MTU4ODc1NDMxNywic3ViIjoiYWRtaW4ifQ.hvaxEG6nKgWrUgxxQoQT5JobnmgpUEeui3aI4TDvvW8

.gitlab-ci.yaml

stages:
  - publish
  - deploy-dev
  - deploy-prod

publish:
  stage: publish
  image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  script:
    - mkdir -p /kaniko/.docker
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"$CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
    - /kaniko/executor --cache=true --context $CI_PROJECT_DIR --dockerfile $CI_PROJECT_DIR/dockerfiles/Dockerfile --destination $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
  only:
    - master

deploy-dev:
  stage: deploy-dev
  image: <private-registry>/dvg-argocli:1
  before_script:
    - git remote set-url origin https://${CI_USERNAME}:${CI_PUSH_TOKEN}@git.nextgen-global.com/$CI_PROJECT_PATH.git
    - git config --global user.email "[email protected]"
    - git config --global user.name "GitLab CI/CD"

  script:
    - git checkout -B master
    - cd deployment/dev
    - kustomize edit set image $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
    - cat kustomization.yaml
    - git commit -am '[skip ci] DEV image update'
    - git push origin master
    - argocd --server $ARGOCD_SERVER --insecure app sync $ARGOCD_APP --auth-token $ARGOCD_AUTH_TOKEN
  only:
    - master

Put deployment gitops to your git repo:

Init deployment and expose service:

kubectl apply -f init_deploy_k8s_svc.yml

Rollback:

Pull image from private registry:

Create secret:

kubectl create secret generic regcred \
    --from-file=.dockerconfigjson=/root/.docker/config.json \
    --type=kubernetes.io/dockerconfigjson -n dev

Or:
kubectl create secret docker-registry regcred --docker-server=<registry-address> --docker-username=<docker-registry-username> --docker-password=<docker-registry-password> --docker-email=<docker-registry-email> -n <namespaces>

kubectl patch serviceaccount default -p '{"imagePullSecrets": [{"name": "regcred"}]}'

Config deployment:

add this to in spec:

      imagePullSecrets:
        - name: regcred

Ref: https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-imagepullsecrets-to-a-service-account

Automated Sync Policy

Ref: https://argoproj.github.io/argo-cd/user-guide/auto_sync/

Source: https://medium.com/@andrew.kaczynski/gitops-in-kubernetes-argo-cd-and-gitlab-ci-cd-5828c8eb34d6