Continuous deployment of containerized applications using GitLab

GitLab is a continuous integration tool. This scenario describes how to build applications in a Docker container and apply Kubernetes resource configurations in GitLab using Yandex.Cloud tools:

Before you start

Create a VM from the GitLab image

Run GitLab on a VM with a public IP address:

  1. On the folder page in management console, click Create resource and select Virtual machine.

  2. In the Name field, enter the VM name: ci-tutorial-gitlab.

  3. Select the availability zone to locate the VM in.

  4. Under Images, click Choose.

  5. In the window that opens, open the DevTools tab.

  6. Choose the GitLab image.

  7. Under Computing resources, specify the following configuration:

    • vCPU: 2
    • Guaranteed vCPU share: 100%
    • RAM: 2 GB
  8. Under Network settings, select the subnet to connect the VM to during creation.

  9. In the Public address field, choose Auto.

  10. Specify data required for accessing the VM:

    • Enter the username in the Login field.
    • In the SSH key field, copy the contents of the public key file. You need to create a key pair for SSH connection yourself. To generate keys, use third-party tools, such as ssh-keygen in Linux and macOS or PuTTygen in Windows.
  11. Click Create VM.

Creating the VM may take several minutes. When the VM status changes to RUNNING, you can start configuring it.

When a VM is created, it is assigned an IP address and hostname (FQDN). You can use this data for SSH access.

Configure GitLab

To configure GitLab and enable Continuous Integration (CI), create a new project and enter parameters to authorize in GitLab CI.

  1. In a browser, open the GitLab admin panel for the created VM. To do this, open a link in the format http://<public-IP-address-of-VM>.
  2. Set the administrator password.
  3. Log in as root with the administrator password.
  4. Select Create a project.
  5. Set the project name: gitlab-test.
  6. Click Create project.

Create resources Kubernetes

Create the Kubernetes resources necessary to run the scripts:

  1. Create a Kubernetes cluster.
  2. Create a Kubernetes node group.

Get a Kubernetes service account token to authenticate with GitLab

To get a service token:

  1. Save the service account creation specification to gitlab-admin-service-account.yaml:

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: gitlab-admin
      namespace: kube-system
    ---
    apiVersion: rbac.authorization.k8s.io/v1beta1
    kind: ClusterRoleBinding
    metadata:
      name: gitlab-admin
    roleRef:
      apiGroup: rbac.authorization.k8s.io
      kind: ClusterRole
      name: cluster-admin
    subjects:
    - kind: ServiceAccount
      name: gitlab-admin
      namespace: kube-system
    
  2. Run the command:

    kubectl apply -f gitlab-admin-service-account.yaml
    
  3. Retrieve the token using the command kubectl describe secret. It will be specified in the token field:

    kubectl -n kube-system describe secret $(kubectl -n kube-system get secret \
    | grep gitlab-admin \
    | awk '{print $1}')
    
  4. Save the token: you need it for the next steps.

Connect the Kubernetes cluster to the GitLab runners

To run your build tasks on a Kubernetes cluster, connect the cluster in the GitLab settings.

  1. In the browser, open a link in the format http://<public-IP-address-of-GitLab-VM>/root.

  2. Select the project named gitlab-test.

  3. In the window that opens on the left, click Operations and select Kubernetes.

  4. Click Add Kubernetes cluster.

  5. In the window that opens click Add existing cluster.

  6. In the Kubernetes cluster name field, enter the cluster name.

  7. In the URL API field, enter the master node address. Retrieve it using the command:

    yc managed-kubernetes cluster get <cluster-id> --format=json \
    | jq -r .master.endpoints.external_v4_endpoint
    
  8. In the CA Certificate field, enter the master certificate. Retrieve it using the command:

    yc managed-kubernetes cluster get my-cluster --format=json \
    | jq -r .master.master_auth.cluster_ca_certificate
    
  9. In the Service Token field, enter the token GitLab will use to create the Kubernetes resources. Use the token you received before you started.

  10. Click Save changes.

  11. Install the applications required for proper operation of GitLab Runner on the Kubernetes cluster:

    • Click Install next to Helm Tiller.
    • Click Install next to GitLab Runner.

Now you can run automated builds inside your Kubernetes cluster.

Read more about Kubernetes cluster connection settings for GitLab builds in the GitLab documentation.

Configure a Docker image build from CI

To build a Docker image, connect to the Docker server.

GitLab lets you define your build scripts in a YAML file. The .gitlab-ci.yml configuration file looks as follows:

build:
  stage: build
  variables:
    DOCKER_DRIVER: overlay2
    DOCKER_TLS_CERTDIR: ""
    DOCKER_HOST: tcp://localhost:2375/
  image: docker:19.03.1
  services:
    - docker:19.03.1-dind
  script:
    - docker build . -t cr.yandex/<registry-id>/<image-name>

Where:

To read more about building Docker images from the CI, see the GitLab Docker integration documentation.

When the build is complete, upload the Docker image to Container Registry to make it available. To do this, authenticate in Container Registry.

Authenticate in Container Registry

There are two ways to authenticate in Container Registry from GitLab Runner:

  • (recommended) Dynamic: Use the metadata service.
  • Static: Use environment variables.

Dynamic

This authentication option only works if the VM with GitLab is linked to a service account. To learn how to link a service account, see Working with Yandex.Cloud from inside an instance.

To allow Docker to get metadata from the metadata service, use a public Docker image named cr.yandex/yc/metadata-token-docker-helper:0.1. It runs Docker credential helper, which gets an IAM token from the metadata service. Use this Docker image while building your app.

The configuration file .gitlab-ci.yml looks as follows:

build:
  stage: build
  variables:
    DOCKER_DRIVER: overlay2
    DOCKER_TLS_CERTDIR: ""
    DOCKER_HOST: tcp://localhost:2375/
  image: cr.yandex/yc/metadata-token-docker-helper:0.1
  services:
    - docker:19.03.1-dind
  script:
    - docker build . -t cr.yandex/<registry-id>/<image-name>
    - docker push cr.yandex/<registry-id>/<image-name>

Static

In the GitLab environment variable, enter the contents of the authorized key for your service account (with the applicable rights) and use this variable when building the Docker image. Learn more about using json-key in Container Registry.

The configuration file .gitlab-ci.yml looks as follows:

build:
  stage: build
  variables:
    DOCKER_DRIVER: overlay2
    DOCKER_TLS_CERTDIR: ""
    DOCKER_HOST: tcp://localhost:2375/
  image: docker:19.03.1
  services:
    - docker:19.03.1-dind
  script:
    - echo <your env-variable> | docker login -u json_key --password-stdin cr.yandex
    - docker build . -t cr.yandex/<registry-id>/<image-name>
    - docker push cr.yandex/<registry-id>/<image-name>

Configure automatic deployment of Kubernetes resources from CI

To set up automatic deployment, specify the master address and service account token in the GitLab settings.

  1. Create the GitLab environment variables:

    • KUBE_URL: The master node address. Retrieve it using the command:

      yc managed-kubernetes cluster get <cluster-id> --format=json \
      | jq -r .master.endpoints.external_v4_endpoint
      
    • KUBE_TOKEN: The token GitLab will use to apply the configuration. Use the token you got before you started.

  2. Use environment variables at the application deployment stage.

    The configuration file .gitlab-ci.yml looks as follows:

    deploy:
      image: gcr.io/cloud-builders/kubectl:latest
      stage: deploy
      script:
        - kubectl config set-cluster k8s --server="$KUBE_URL" --insecure-skip-tls-verify=true
        - kubectl config set-credentials admin --token="$KUBE_TOKEN"
        - kubectl config set-context default --cluster=k8s --user=admin
        - kubectl config use-context default
        - kubectl apply -f k8s.yaml
    

Now, every time you run an automated build, a task to change the Kubernetes resource configuration is created.

See also