Available 24×7

Mon → Sun : 00:01am-11:59pm

Email: [email protected]

Facebook

Twitter

LinkedIn

Youtube

Instagram


Complete CI/CD Laravel Apps Using Gitlab CI To GKE: Image Build

GitLab CI/CD has many functions, although the primary goal of the tool is to build a continuous environment using these methodologies:

Stages & Requirements

The complete CI/CD flow is divided into several stages and requirements. The requirements are for you to have the following entities:

  • Gitlab SaaS account or Self-hosted account
  • A registry to save the image-build (you can use a public registry such as a Docker registry)
  • Kubernetes cluster spawn using GKE
  • GitLab pipeline to build the flow

Whereas the stages of CI/CD development are explained as the following:

  • Build Stage: The stage to build the required image as a service, such as Nginx Image to serve as a web server, fpm image to process the PHP script execution, etc
  • Test Stage / Scan Test: The stage to test of the build result for the related image
  • Deploy Stage: The stage to deliver the image build to the Kubernetes cluster

build Stage

If you’ve done created an account for GitLab, please create file .gitlab-ci.yaml on your working branch or the main branch.

Example Directory structure for image build
  • Ubuntu Build
## Ubuntu Build Dockerfile
FROM ubuntu:22.04

# Init preparation
RUN apt-get update && apt-get upgrade -y \
        && apt-get install software-properties-common apt-transport-https less net-tools telnet -y \
        && add-apt-repository ppa:ondrej/php -y && apt-get update \
        && apt-get install inetutils-ping vim nano wget \
        zip gnupg mysql-client -y
  • FPM Build
## FPM Build Dockerfile
FROM index.docker.io/sultanahmad/ubuntu-base:v4

# Init preparation
RUN apt-get update && apt-get upgrade -y \
        && apt-get install php8.0 php8.0-common php8.0-cli php8.0-xml php8.0-mysql \
        php8.0-mbstring php8.0-bcmath php8.0-fpm php8.0-readline php8.0-curl -y 
#

# Config PHP-FPM
WORKDIR /etc/php/8.0/fpm/pool.d
RUN cp www.conf www.conf.orig
RUN sed -i "s/\/run\/.*/0.0.0.0:9000/g" www.conf && service php8.0-fpm start
#

# Data migration and preparation
WORKDIR /usr/local/bin
RUN wget https://getcomposer.org/download/2.4.2/composer.phar
RUN mv composer.phar composer && chmod +x composer

RUN mkdir -pv /var/www/html/travellist
RUN mkdir -pv /apps

COPY web-data/ /apps/
WORKDIR /apps
RUN echo yes | composer install
  • Nginx Build
## Nginx Build Dockerfile
FROM nginx:latest

RUN apt-get update \
    && apt-get install inetutils-ping mysql-common vim nano -y

Full example code of the build pipeline is as the following lines:

variables:
  IMAGE_TAG1: "v3"
  KUBE_AGENT_PATH: linuxsa/epic-developer-advocate/kube-agents
  IMAGE_NGINX: "index.docker.io/sultanahmad/laravel-nginx:$IMAGE_TAG1"
  IMAGE_FPM: "index.docker.io/sultanahmad/laravel-fpm:$CI_BUILD_REF_NAME"
  IMAGE_UBUNTU: "index.docker.io/sultanahmad/ubuntu-base:$CI_BUILD_REF_NAME"
  NGINX_PATH: "laravel-build/nginx-build/Dockerfile"
  FPM_PATH: "laravel-build/fpm-build/Dockerfile"
  FPM_PATH_STAGING: "laravel-build/fpm-build/Dockerfile.staging"
  UBUNTU_PATH_STAGING: "ubuntu-build/Dockerfile.staging"
  UBUNTU_PATH: "ubuntu-build/Dockerfile"
  CI_REGISTRY: "index.docker.io"
  UBUNTU_CONTEXT_DIR: "dir://ubuntu-build"
  FPM_CONTEXT_DIR: "dir://laravel-build/fpm-build"
  NGINX_CONTEXT_DIR: "dir://laravel-build/nginx-build"
  SAST_IMAGE_SUFFIX: '-fips'
  SAST_EXCLUDED_ANALYZERS: "spotbugs, bandit, brakeman, gosec, semgrep, security-code-scan, flawfinder"

stages:
  - build
  - release

build-ubuntu-image:
  image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  stage: build
  environment: staging
  script:
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
    - /kaniko/executor
      --context=$UBUNTU_CONTEXT_DIR
      --dockerfile=$UBUNTU_PATH_STAGING
      --destination "${IMAGE_UBUNTU}"
  tags:
    - mamad
  rules:
    - if: $CI_COMMIT_TAG
    - if: $CI_COMMIT_TITLE =~ /^redeploy/
    - if: $CI_COMMIT_TITLE =~ /^build image/

build-fpm-image:
  image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  stage: build
  environment: staging
  variables:
    APP_URL: travellist-staging.ahmadcloud.my.id
  needs: [build-ubuntu-image]
  before_script:
    - sh laravel-build/script.sh
  script:
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
    - /kaniko/executor
      --context=$FPM_CONTEXT_DIR
      --dockerfile=$FPM_PATH_STAGING
      --destination "${IMAGE_FPM}"
  tags:
    - mamad
  rules:
    - if: $CI_COMMIT_TAG
    - if: $CI_COMMIT_TITLE =~ /(?:^|\W)redeploy(?:$|\W)/
    - if: $CI_COMMIT_TITLE =~ /^build image/

build-nginx-image:
  image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  stage: build
  before_script:
    - echo $CI_PROJECT_DIR
  script:
    - echo "{\"auths\":{\"$CI_REGISTRY\":{\"username\":\"$CI_REGISTRY_USER\",\"password\":\"CI_REGISTRY_PASSWORD\"}}}" > /kaniko/.docker/config.json
    - /kaniko/executor
      --context=$NGINX_CONTEXT_DIR
      --dockerfile=$NGINX_PATH
      --destination "${IMAGE_NGINX}"
  tags:
    - mamad
  rules:
    - if: $CI_COMMIT_TAG
    - if: $CI_COMMIT_TITLE =~ /(?:^|\W)redeploy(?:$|\W)/
    - if: $CI_COMMIT_TITLE =~ /^build image/

# Image Production Release
release:
  image:
    name: gcr.io/kaniko-project/executor:debug
    entrypoint: [""]
  stage: release
  variables:
    RELEASE_IMAGE_FPM: "$REGISTRY/$GCR_PROJECT/laravel-fpm:$IMAGE_TAG1"
    RELEASE_IMAGE_UBUNTU: "$REGISTRY/$GCR_PROJECT/ubuntu-base:$IMAGE_TAG1"
    APP_URL: travellist.ahmadcloud.my.id
    DB_USER: user_db
  before_script:
    - sh laravel-build/script.sh
    - export GOOGLE_APPLICATION_CREDENTIALS=/kaniko/config.json
    - base64 -d "$GCR_ACCOUNT" > $GOOGLE_APPLICATION_CREDENTIALS
  environment: production
  script:
    - /kaniko/executor
      --context=$UBUNTU_CONTEXT_DIR
      --dockerfile=$UBUNTU_PATH
      --destination "${RELEASE_IMAGE_UBUNTU}"

    - /kaniko/executor
      --context=$FPM_CONTEXT_DIR
      --dockerfile=$FPM_PATH
      --destination "${RELEASE_IMAGE_FPM}"

  when: manual
  tags:
    - mamad
  rules:
    - if: $CI_COMMIT_TAG
    - if: $CI_COMMIT_TITLE =~ /^redeploy/
    - if: $CI_COMMIT_TITLE =~ /^build image/
    - if: $CI_COMMIT_TITLE =~ /^release image/
Explanation
  • The job described on the pipeline above will build an FPM Image, based on the custom Ubuntu build image
  • The image registry will be at the Docker registry
  • The pipeline for image build is divided into two stages, the build stage is a stage to build the image with the tag <image tag name>:$IMAGE_TAG1, while the release stage is a ready image for production purposes. The image tag for the second stage will have a version number on the end of the name, e.g <image tag name>:$IMAGE_TAG2
  • Each image build job in gitlab-ci, is triggered by a specified commit title so that the job will not get into the pipeline on every commit
  • There is a line to execute the script to replace the image tag from Dockerfile (sh laravel-build/script.sh). That strategy allows us to modify the image tag name dynamically by only changing the variable on gitlab-ci.yaml

Pipeline Result

Conclusion

In this part, we have explained the pipeline and the Dockerfile jobs to build the image for the containerized applications.

In the next part, we will have an article to explain the SAST and the continuous delivery integration using GitLab CI.

For more articles and tutorials please visit our website at settingserver.com.

If you have any more inquiries please reach out to us at [email protected]

References

One response

  1. […] This section is a part two series of Complete CI/CD Laravel Apps Using Gitlab CI To GKE. For those who haven’t read the previous article, please follow this link Complete CI/CD Laravel Apps Using Gitlab CI To GKE: Image Build. […]

Leave a Reply

Your email address will not be published. Required fields are marked *