Day 13 of my 90-Devops project: Setting Up a CI/CD Pipeline with Docker and Kubernetes on GitLab
Tags: gitlab, cicd, docker, kubernetes
Published: 2024-07-16 22:41:02



#### Prerequisites
1. **Basic Knowledge of Docker and Kubernetes**
2. **GitLab Account**
3. **Git Installed on Local Machine**
4. **Docker Installed on Local Machine**
5. **Minikube Installed on Local Machine**
6. **kubectl Installed on Local Machine**

### Step 1: Setting Up the Project

1. **Create a Project Directory**
    ```bash
    mkdir day13secureci
    cd day13secureci
    ```

2. **Initialize a Git Repository**
    ```bash
    git init
    ```

3. **Create a Dockerfile**
    ```bash
    touch Dockerfile
    ```
    **Content of Dockerfile**:
    ```dockerfile
    # Use an official Node.js runtime as a parent image
    FROM node:14

    # Set the working directory
    WORKDIR /usr/src/app

    # Copy package.json and package-lock.json
    COPY package*.json ./

    # Install dependencies
    RUN npm install

    # Copy the rest of the application code
    COPY . .

    # Expose port 8080
    EXPOSE 8080

    # Run the application
    CMD ["node", "app.js"]
    ```

4. **Create Kubernetes Deployment and Service Files**
    ```bash
    mkdir -p kubernetes
    touch kubernetes/deployment.yaml
    touch kubernetes/service.yaml
    ```

    **Content of deployment.yaml**:
    ```yaml
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: my-app-deployment
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: my-app
      template:
        metadata:
          labels:
            app: my-app
        spec:
          containers:
          - name: my-app
            image: registry.gitlab.com/your-username/your-project-name:my-app:latest
            ports:
            - containerPort: 8080
    ```

    **Content of service.yaml**:
    ```yaml
    apiVersion: v1
    kind: Service
    metadata:
      name: my-app-service
    spec:
      selector:
        app: my-app
      ports:
        - protocol: TCP
          port: 80
          targetPort: 8080
      type: LoadBalancer
    ```

5. **Create GitLab CI/CD Configuration File**
    ```bash
    touch .gitlab-ci.yml
    ```

    **Content of .gitlab-ci.yml**:
    ```yaml
    stages:
      - build
      - test
      - deploy

    variables:
      DOCKER_DRIVER: overlay2

    before_script:
      - docker info

    build:
      stage: build
      script:
        - docker build -t my-app .
        - docker tag my-app:latest registry.gitlab.com/your-username/your-project-name:my-app:latest
        - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN registry.gitlab.com
        - docker push registry.gitlab.com/your-username/your-project-name:my-app:latest

    test:
      stage: test
      script:
        - docker run --rm my-app npm test

    deploy:
      stage: deploy
      script:
        - kubectl apply -f kubernetes/deployment.yaml
        - kubectl apply -f kubernetes/service.yaml
      environment:
        name: production
        url: http://your-app-url.com
    ```

6. **Create Your Application Code**
    - Create a simple Node.js application:

    ```bash
    touch app.js
    ```

    **Content of app.js**:

    ```javascript
    const express = require('express');
    const app = express();
    const port = 8080;

    app.get('/', (req, res) => {
      res.send('Hello, World!');
    });

    app.listen(port, () => {
      console.log(`App running on http://localhost:${port}`);
    });
    ```

    **Create package.json**:

    ```bash
    touch package.json
    ```
    **Content of package.json**:
    ```json
    {
      "name": "my-app",
      "version": "1.0.0",
      "description": "A simple Node.js app",
      "main": "app.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "dependencies": {
        "express": "^4.17.1"
      }
    }
    ```

### Step 2: Setting Up GitLab

1. **Create a New Project on GitLab**
    - Log in to your GitLab account and create a new project.

2. **Connect Your Local Repository to GitLab**
    ```bash
    git remote add origin https://gitlab.com/your-username/your-project-name.git
    git add .
    git commit -m "Initial commit"
    git push -u origin master
    ```

### Step 3: Running the Pipeline Locally

Since GitLab CI/CD runs in a CI environment and cannot directly interact with your local Minikube cluster, you’ll need to simulate the pipeline locally or adjust your setup for local testing.

1. **Create a Script to Run the CI/CD Steps Locally**
    ```bash
    touch run_pipeline.sh
    ```

    **Content of run_pipeline.sh**:
    ```bash
    #!/bin/bash

    # Set variables
    IMAGE_NAME="my-app"
    REGISTRY="registry.gitlab.com"
    USERNAME="your-username"
    PROJECT_NAME="your-project-name"
    IMAGE_TAG="${REGISTRY}/${USERNAME}/${PROJECT_NAME}:${IMAGE_NAME}"

    # Build Docker image
    echo "Building Docker image..."
    docker build -t ${IMAGE_NAME} .

    # Tag the Docker image
    echo "Tagging Docker image..."
    docker tag ${IMAGE_NAME}:latest ${IMAGE_TAG}:latest

    # Log in to GitLab container registry
    echo "Logging in to GitLab container registry..."
    docker login -u your-gitlab-username -p your-gitlab-password ${REGISTRY}

    # Push the Docker image to the registry
    echo "Pushing Docker image to registry..."
    docker push ${IMAGE_TAG}:latest

    # Run tests (assuming you have a test script)
    echo "Running tests..."
    docker run --rm ${IMAGE_TAG}:latest npm test

    # Deploy to Minikube
    echo "Deploying to Minikube..."
    kubectl apply -f kubernetes/deployment.yaml
    kubectl apply -f kubernetes/service.yaml

    echo "Pipeline execution completed."
    ```

2. **Make the Script Executable**
    ```bash
    chmod +x run_pipeline.sh
    ```

3. **Run the Script**
    ```bash
    ./run_pipeline.sh
    ```

### Step 4: Verify Deployment on Minikube

1. **Start Minikube**
    ```bash
    minikube start
    ```

2. **Check the Deployment and Service**
    ```bash
    kubectl get deployments
    kubectl get services
    ```

### Common Issues and Troubleshooting

1. **Dockerfile Not Found**
    - Ensure the `Dockerfile` is in the project root directory and named correctly.

2. **Invalid Repository/Tag Format**
    - Ensure you have replaced placeholder values with actual GitLab username and project name.

3. **Missing Kubernetes Files**
    - Verify that `kubernetes/deployment.yaml` and `kubernetes/service.yaml` exist and have the correct content.

### Final Notes

- Ensure all paths and filenames are correct.
- Replace all placeholder values with your actual values.
- Follow the steps sequentially to avoid errors.