Skip to content

PoC: Rollout application server

Hossein Pursultani requested to merge rollout-app-server-deployment into main

🛑 This is a PoC. Do not merge.

What does this MR do?

Similar to GitLab Chart, Puma and Workhorse run together in a single Pod. The workload is managed by a Deployment and exposed through a Service and Ingress resource.

This change enables controller to create the Deployment, Service, and Ingress resources for the application server.

Validation

To validate this PoC, follow these steps:

  1. Deploy a minimal GitLab instance with GitLab Chart, including its external dependencies, i.e. PostgreSQL, Redis, and MinIO.
  2. Install GitLab Operator V2 and v2alpha1 CRD from source and the manifest of this MR.
  3. Remove Puma and Workhorse resources (Deployment, Service, Ingress, etc) that GitLab Chart is created.
  4. Create a v2alpha1 GitLab custom resource.
  5. Allow Operator to install Puma and Workhorse.
  6. Check the GitLab instance is still functioning.

Step 1

export RELEASE='operator-v2-dev-kit'
export NAMESPACE='operator-v2-test'
CHART_VERSION='7.11.2' # GitLab 16.11.2

# Enter your domain name and email address for GitLab instance

read -s DOMAIN
read -s EMAIL

# Running Helm command to install the GitLab instance.
# The unused components are disabled.

helm upgrade "${RELEASE}" gitlab/gitlab \
    --version "${CHART_VERSION}" \
    --install \
    --create-namespace \
    -n "${NAMESPACE}" \
    --timeout 600s \
    --set "global.hosts.domain=${DOMAIN}" \
    --set "certmanager-issuer.email=${EMAIL}" \
    --set 'gitlab.gitlab-shell.enabled=false' \
    --set 'gitlab.mailroom.enabled=false' \
    --set 'global.kas.enabled=false' \
    --set 'global.pages.enabled=false' \
    --set 'global.registry.enabled=false' \
    --set 'global.spamcheck.enabled=false' \
    --set 'gitlab-runner.install=false' \
    --set 'prometheus.install=false'

# Wait for GitLab instance to start ⏳

# Checking logs of webservice Pods ...

stern -n ${NAMESPACE} webservice -s 2s

Step 2

First, checkout the source from the branch of this MR.

TAG='rollout-app-server-deployment'

# This is the image tag for the PoC

make build \
  deploy \
  TAG="${TAG}"

# Check GitLab CRD and Operator's controller-manager logs

kubectl api-resources | grep gitlab

OPERATOR_NAMESPACE='gitlab-operator-v2-system'
stern -n ${OPERATOR_NAMESPACE} -c manager controller-manager

Port Secrets before Step 3

The current implementation in the PoC does not generate Secrets. Therefore, before creating a GitLab custom resource, you need port some of the Secrets that GitLab Chart has generated:

  1. For PostgreSQL and Redis authentication, V2 uses kubernetes.io/basic-auth Secret type. We need to copy the content from Opaque types.

  2. Rails and Workhorse Secrets must be copied as well. This is a shortcoming of the PoC and will be fixed in the next iteration.

    There is a also minor difference between Chart and Operator that requires renaming Secret keys.

## Helper functions for porting Secrets
get_secret_value() {
  local secret_name="${1}"
  local field_name="${2}"

  kubectl -n "${NAMESPACE}" get secret "${RELEASE}-${secret_name}" \
    -o jsonpath="{.data.${field_name}}" | base64 -d
}

create_basic_auth_secret() {
  local secret_name="${1}"
  local username="${2}"
  local password="${3}"

  kubectl apply -f - <<EOF
apiVersion: v1
kind: Secret
metadata:
  name: ${secret_name}
  namespace: ${NAMESPACE}
type: kubernetes.io/basic-auth
stringData:
  username: ${username}
  password: ${password}
EOF
}

create_opaque_secret() {
  local secret_name="${1}"
  local key="${2}"
  local value="${3}"

  kubectl -n ${NAMESPACE} create secret generic ${secret_name} --from-literal "${key}=${value}"

Use the helper functions to port Secrets:

# PostgreSQL password authentication. Username is `gitlab`.
create_basic_auth_secret 'example-1-postgresql-auth' \
  'gitlab' "$(get_secret_value 'postgresql-password' 'postgresql\-password')"

# Redis password authentication. Username is empty (``), i.e. default user.
create_basic_auth_secret 'example-1-redis-auth' \
  '' "$(get_secret_value 'redis-secret' 'secret')"

# Copying `secrets.yml` key of Rails Secret to a new Secret with `secrets.yaml` key
create_opaque_secret 'example-1-rails-secret' \
  'secrets.yaml' "$(get_secret_value 'rails-secret' 'secrets\.yml')"

# Moving `shared_secret` key of Workhorse Secret to a new Secret with `secret` key
create_opaque_secret 'example-1-workhorse-secret' \
  'secret' "$(get_secret_value 'gitlab-workhorse-secret' 'shared_secret')"

Define a default IngressClass before Step 3

The PoC does not integrate with an Ingress provider. Therefore, it needs a default IngressClass to function properly.

kubectl annotate ingressclasses --overwrite -l release=${RELEASE} \
  'ingressclass.kubernetes.io/is-default-class'='true'

Step 3

Remove Puma and Workhorse resources that GitLab Chart created.

kubectl -n ${NAMESPACE} delete ingress -l app=webservice
kubectl -n ${NAMESPACE} delete service -l app=webservice
kubectl -n ${NAMESPACE} delete hpa -l app=webservice
kubectl -n ${NAMESPACE} delete deployment -l app=webservice

Step 4

Use the following GitLab resource:

# example-1.yaml
apiVersion: gitlab.com/v2alpha1
kind: GitLab
metadata:
  name: example-1
spec:
  version: 16.11.2
  externalUrl: https://gitlab.<DOMAIN>

  # Using TLS certificate from CertManager that
  # is created with GitLab Chart installation.
  tls:
    certificate:
      name: operator-v2-dev-kit-gitlab-tls

  postgresql:
    name: default
    provider:
      # This PostgreSQL is installed with GitLab Chart.
      service:
        name: operator-v2-dev-kit-postgresql

    authentication:
      # This is the Secret that we ported before.
      basic:
        name: example-1-postgresql-auth

  redis:
    name: default
    provider:
      # This Redis is installed with GitLab Chart.
      service:
        name: operator-v2-dev-kit-redis-master

    authentication:
      # This is the Secret that we ported before.
      basic:
        name: example-1-redis-auth

  # Gitaly
  repository:
    name: default
    provider:
      # This Gitaly is installed with GitLab Chart.
      service:
        name: operator-v2-dev-kit-gitaly

    # Reusing the same Secret from GitLab Chart.
    authentication:
      token:
        name: operator-v2-dev-kit-gitaly-secret
        key: token

  appServer:
    # See how we use a PodTemplateSpec to define the template
    # of the workload.
    podTemplate:
      spec:
        containers: []
        securityContext:
          runAsUser: 1000
          runAsGroup: 1000
          fsGroup: 1000

  appConfig:
    objectStore:
      provider:
        # Use MinIO that is installed with GitLab Chart.
        aws:
          accessKeyId:
            name: operator-v2-dev-kit-minio-secret
            key: accesskey
          accessKeySecret:
            name: operator-v2-dev-kit-minio-secret
            key: secretkey
          region: 'local'
          endpoint: http://operator-v2-dev-kit-minio-svc.operator-v2-test.svc:9000

      destinations:
        artifacts:
          bucketName: example-1-artifacts
        externalDiffs:
          bucketName: example-1-external-diffs
        lfs:
          bucketName: example-1-lfs
        uploads:
          bucketName: example-1-uploads
        packages:
          bucketName: example-1-packages
        dependencyProxy:
          bucketName: example-1-dependency-proxy
        terraformStates:
          bucketName: example-1-terraform-states
        ciSecureFiles:
          bucketName: example-1-ci-secure-files

And apply the changes:

kubectl apply -f example-1.yaml

kubectl get gitlabs

Step 5

Allow Operator to install Puma and Workhorse.

stern -n ${OPERATOR_NAMESPACE} -c manager controller-manager

Wait for GitLab reconciler to finish

Step 6

Check the resources that the controller created.

kubectl -n ${NAMESPACE} get secret | grep ${RESOURCE_NAME}
kubectl -n ${NAMESPACE} get deployment -l 'app.kubernetes.io/component'='application-server'
kubectl -n ${NAMESPACE} get service -l 'app.kubernetes.io/component'='application-server'
kubectl -n ${NAMESPACE} get ingress -l 'app.kubernetes.io/component'='application-server'

And verify the instance is still working with the existing data:

stern -n ${NAMESPACE} application-server -s 10m

Further work

  1. Generate Puma and Workhorse Secrets.
  2. Integrate with Ingress provider.

Author's Checklist

For anything in this list which will not be completed, please provide a reason in the MR discussion.

Required

  • Ensure a release milestone is set.
  • MR title and description are up to date, accurate, and descriptive.
  • MR targeting the appropriate branch.
  • MR has a green pipeline on GitLab.com.
  • When ready for review, MR is labeled workflowready for review per the MR workflow.

Expected

  • Test plan indicating conditions for success has been posted and passes.
  • Documentation is created or updated.
  • Tests are added.

Related issues

Related to #2

Edited by Hossein Pursultani

Merge request reports