Feedback

Chat Icon

DevSecOps in Practice

A Hands-On Guide to Operationalizing DevSecOps at Scale

Setting Up the Foundation: Kubernetes Manifests
41%

Creating the Deployment Manifests

After pushing the Docker images to the container registry, we can now deploy our two microservices to the cluster. We will start by creating the deployment manifests for the menu service.

Before creating the deployment manifests, we need to have an external access point to the cluster. We can use an Nginx Ingress controller for this purpose. Start by installing it using Helm.

Add the Ingress Nginx repository:

helm repo add ingress-nginx \
  https://kubernetes.github.io/ingress-nginx

Create a values file for the Ingress Nginx controller:

# Create a folder for the Kubernetes deployment files
mkdir -p $HOME/RestQR/deploy/kubernetes

# Create a values file for the Ingress controller
cat <$HOME/RestQR/deploy/kubernetes/ingress-values.yaml
controller:
  service:
    type: LoadBalancer
EOF

Install the controller:

helm upgrade \
  --install \
  ingress-nginx \
  ingress-nginx/ingress-nginx \
  --values $HOME/RestQR/deploy/kubernetes/ingress-values.yaml

Get the external IP address of the Ingress controller and export it as an environment variable:

# Wait for the external IP address to be assigned
while true; do
    INGRESS_IP=$(kubectl get svc ingress-nginx-controller \
        -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
    if [[ -n "$INGRESS_IP" ]]; then
        break
    fi
    sleep 2
done

# Export the Ingress IP address as an environment variable
echo "export INGRESS_IP=$INGRESS_IP" >> ~/.bashrc
source ~/.bashrc

Let's move to the application. Create a file called menu-deployment.yaml using the following command:

cat <$HOME/RestQR/deploy/kubernetes/menu-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  # Name of the Deployment
  name: menu  
  labels:
    # Label to identify the application
    app: menu  

spec:
  # Number of desired pod replicas (1 instance of the menu service)
  replicas: 1  
  selector:
    matchLabels:
      # Ensures that the Deployment manages pods with this label
      app: menu  

  template:
    metadata:
      labels:
        # Label assigned to the pod created by this template
        app: menu  

    spec:
      containers:
      # Name of the container inside the pod
      - name: menu  
        # Image location from GitLab Container Registry
        image: $GITLAB_REGISTRY_URL/menu-service:v0.1.0  
        # Always pull the image from the registry
        imagePullPolicy: Always
        ports:
        # The application inside the container listens on port 5000
        - containerPort: 5000  

        env:
        # Environment variable for database connection
        - name: DATABASE_URL  
          valueFrom:
            secretKeyRef:
              # Reference to the Kubernetes secret containing the database URL
              name: menu-secret  
              # The specific key inside the secret
              key: DATABASE_URL  

      # Image Pull Secret for GitLab Container Registry authentication
      imagePullSecrets:
      # Kubernetes secret containing GitLab credentials
      - name: gitlab-registry-secret  
EOF

The above manifest defines a Deployment for the menu service. It specifies that the Deployment should manage one pod with the menu label. The pod runs a container with the menu-service image from the GitLab Container Registry. The container listens on port 5000 and has an environment variable called DATABASE_URL that references a Kubernetes secret called menu-secret. The secret contains the database URL. To pull the image from the GitLab Container Registry, the manifest specifies an image pull secret called gitlab-registry-secret. As you may have noticed, we have not created the secrets yet. We will do this in the next steps.

To create a Secret for the database URL, use the following command:

cat <$HOME/RestQR/deploy/kubernetes/menu-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: menu-secret
type: Opaque
data:
  DATABASE_URL: $(echo -n "postgresql://menu-user:menu-password@menu-postgresql:5432/menu-database" | base64 -w 0)
EOF

The above manifest creates a Secret called menu-secret with the database connection string encoded using base64. The connection string contains the username menu-user, password menu-password, and database name menu-database. The database is running on the menu-postgresql service on port 5432. The connection string is in the format postgresql://username:password@hostname:port/database.

We also need to create the pull secret for the GitLab Container Registry. Before doing this, make sure you have the GitLab credentials in a file called config.json in the .docker folder in your home directory (cat $HOME/.docker/config.json). If you don't have this file, you can create it by running the following command:

# Run this only if you don't have the config.json file
mkdir -p $HOME/.docker && cat <$HOME/.docker/config.json
{
  "auths": {
    "registry.gitlab.com": {
      "auth": "$(echo -n "$GITLAB_USERNAME:$GITLAB_API_TOKEN" | base64 -w 0)"
    }
  }
}
EOF

Now create the pull secret for the GitLab Container Registry:

cat <$HOME/RestQR/deploy/kubernetes/gitlab-registry-secret.yaml
apiVersion: v1
kind: Secret
metadata:
  name: gitlab-registry-secret
  namespace: default
  labels:
    app: menu
  annotations:
    kubernetes.io/service-account.name: gitlab-registry-secret

type: kubernetes.io/dockerconfigjson
data:
  .dockerconfigjson: $(cat $HOME/.docker/config.json | base64 -w 0)
EOF

We need to create a service for the menu service to expose it to other services in the cluster. Create a file called menu-service.yaml in the RestQR/menu/kube folder:

cat <$HOME/RestQR/deploy/kubernetes/menu-service.yaml
apiVersion: v1
kind: Service
metadata:
  name: menu
  namespace: default
  labels:
    app: menu
spec:
  selector:
    app: menu
  ports:
    - protocol: TCP
      port: 5000
      targetPort: 5000
EOF

We will now create the deployment manifests for the qr service. Start by creating a file called qr-deployment.yaml in the RestQR/deploy/kubernetes folder:

cat <$HOME/RestQR/deploy/kubernetes/qr-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: qr
  namespace: default
  labels:
    app: qr
spec:
  replicas: 1
  selector:
    matchLabels:
      app: qr
  template:
    metadata:
      labels:
        app: qr
    spec:
      containers:
      - name: qr
        image: $GITLAB_REGISTRY_URL/qr-service:v0.1.0
        imagePullPolicy: Always
        ports:
        - containerPort: 5001
        env:
        - name: MENU_BASE_URL
          valueFrom:
            configMapKeyRef:
              name: qr-config
              key: MENU_BASE_URL
      imagePullSecrets:
      - name: gitlab-registry-secret
EOF

Same as the menu service, the above manifest defines a Deployment for the qr service. It specifies that the Deployment should manage one pod with the qr label. The pod runs a container with the qr-service image from the GitLab Container Registry. The container listens on port 5001. To pull the image from the GitLab Container Registry, the manifest specifies an image pull secret called gitlab-registry-secret. The container has an environment variable called MENU_BASE_URL that references a ConfigMap called qr-config. We will now create the ConfigMap:

cat <$HOME/RestQR/deploy/kubernetes/qr-config.yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: qr-config
  namespace: default
data:

DevSecOps in Practice

A Hands-On Guide to Operationalizing DevSecOps at Scale

Enroll now to unlock current content and receive all future updates for free. Your purchase supports the author and fuels the creation of more exciting content. Act fast, as the price will rise as the course nears completion!