- 
                Notifications
    
You must be signed in to change notification settings  - Fork 61
 
Dockerizing Applications and PR CI CD Setup
This documentation provides a comprehensive guide for Dockerizing applications and configuring CI/CD pipelines using GitHub Actions. It covers the steps for containerizing backend and frontend applications, setting up environment-specific Docker Compose files, and automating deployments with GitHub Actions.
To containerize your backend and frontend applications and set up Docker Compose for seamless development and deployment.
- Backend Dockerfile: Define the environment and instructions for building the backend container.
 - Frontend Dockerfile: Define the environment and instructions for building the frontend container.
 
FROM php:8.2-fpm
RUN apt-get update && apt-get install -y \
    libpng-dev \
    libjpeg-dev \
    libfreetype6-dev \
    libzip-dev \
    libpq-dev \
    git \
    unzip \
    && rm -rf /var/lib/apt/lists/*
RUN pecl install apcu \
    && docker-php-ext-enable apcu
RUN docker-php-ext-configure gd --with-freetype --with-jpeg \
    && docker-php-ext-install gd zip pdo pdo_pgsql
COPY php.ini /usr/local/etc/php/conf.d/custom.ini
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
WORKDIR /var/www/html
COPY . /var/www/html
RUN composer install --no-interaction --prefer-dist --optimize-autoloader
RUN cp .env.example .env
RUN echo "apc.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-apcu.ini
CMD ["sh", "-c", "nohup php artisan serve --host=0.0.0.0 "]
FROM node:20-alpine AS base
WORKDIR /app
COPY . .
RUN npm install -g pnpm 
RUN pnpm install
RUN pnpm run build
EXPOSE 3000
CMD ["node", "server.js"]
Define a docker-compose.yml file at the root of your project to orchestrate services including backend, frontend, databases, proxy, and Redis.
services:
  app:
    build:
      context: .
    ports:
      - "8000:8000"
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    environment:
      - APP_ENV=production
      - APP_DEBUG=false
      - DB_CONNECTION=pgsql
      - DB_HOST=db
      - DB_PORT=5432
      - DB_DATABASE=app
      - DB_USERNAME=app
      - DB_PASSWORD=changethis123
      - QUEUE_CONNECTION=redis
      - REDIS_HOST=redis
      - REDIS_PORT=6379
  db:
    image: postgres:latest
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: changethis123
      POSTGRES_DB: app
    ports:
      - "5432:5432"
    volumes:
      - db_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 10s
      retries: 5
      start_period: 30s
      timeout: 5s
  proxy:
    image: 'jc21/nginx-proxy-manager:latest'
    restart: always
    ports:
      - '8090:81'
    volumes:
      - ./nginx/conf:/etc/nginx/conf.d
      - ./certs:/etc/nginx/letsencrypt
      - /var/run/docker.sock:/tmp/docker.sock:ro
  redis:
    image: redis:latest
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      retries: 3
      start_period: 30s
      timeout: 5s
  redis-commander:
    image: rediscommander/redis-commander:latest
    ports:
      - "8081:8081"
    environment:
      - REDIS_HOSTS=local:redis:6379
  adminer:
    image: adminer:latest
    ports:
      - "8080:8080"
    environment:
        ADMINER_DEFAULT_SEVERAL: db
  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./fastcgi-php.conf:/etc/nginx/snippets/fastcgi-php.conf
    depends_on:
      - "app"
volumes:
  db_data:
Ensure services communicate properly with each other.
These will manage different configurations for staging and production environments by using environment-specific Docker Compose files.
- 
Create docker-compose.staging.yml Configure services and settings tailored for the staging environment.
 - 
Create docker-compose.production.yml Configure services and settings tailored for the production environment.
 
###Docker-compose.staging.yml:
version: '3.8'
services:
  app-delve:
    image: delve_be:latest
    ports:
      - "8000:8000"
    depends_on:
      db-delve:
        condition: service_healthy
      redis-delve:
        condition: service_healthy
    environment:
      - APP_ENV=staging
      - APP_DEBUG=true
      - DB_CONNECTION=pgsql
      - DB_HOST=db
      - DB_PORT=5432
      - DB_DATABASE=app_staging
      - DB_USERNAME=app_staging
      - DB_PASSWORD=changethis123
      - QUEUE_CONNECTION=redis
      - REDIS_HOST=redis
      - REDIS_PORT=6379
      - WWWGROUP=1000
      - WWWUSER=1000
  db-delve:
    image: postgres:latest
    environment:
      POSTGRES_USER: app_staging
      POSTGRES_PASSWORD: changethis123
      POSTGRES_DB: app_staging
    ports:
      - "5400:5432"
    volumes:
      - db-delve_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app_staging"]
      interval: 10s
      retries: 5
      start_period: 30s
      timeout: 5s
      
  redis-delve:
    image: redis:latest
    ports:
      - "6374:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      retries: 3
      start_period: 30s
      timeout: 5s
  adminer:
    image: adminer:latest
    ports:
      - "8080:8080"
    environment:
        ADMINER_DEFAULT_SEVERAL: db
  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./fastcgi-php.conf:/etc/nginx/snippets/fastcgi-php.conf
    depends_on:
      - "app"
  proxy:
    image: 'jc21/nginx-proxy-manager:latest'
    restart: always
    ports:
      - '8090:81'
    volumes:
      - ./nginx/conf:/etc/nginx/conf.d
      - ./certs:/etc/nginx/letsencrypt
      - /var/run/docker.sock:/tmp/docker.sock:ro
volumes:
  db-delve_data:
version: '3.8'
services:
  app:
    build:
      context: .
    ports:
      - "8000:8000"
    depends_on:
      db:
        condition: service_healthy
      redis:
        condition: service_healthy
    environment:
      - APP_ENV=production
      - APP_DEBUG=false
      - DB_CONNECTION=pgsql
      - DB_HOST=db
      - DB_PORT=5432
      - DB_DATABASE=app
      - DB_USERNAME=app
      - DB_PASSWORD=changethis123
      - QUEUE_CONNECTION=redis
      - REDIS_HOST=redis
      - REDIS_PORT=6379
  db:
    image: postgres:latest
    environment:
      POSTGRES_USER: app
      POSTGRES_PASSWORD: changethis123
      POSTGRES_DB: app
    ports:
      - "5432:5432"
    volumes:
      - db_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 10s
      retries: 5
      start_period: 30s
      timeout: 5s
  proxy:
    image: 'jc21/nginx-proxy-manager:latest'
    restart: always
    ports:
      - '8090:81'
    volumes:
      - ./nginx/conf:/etc/nginx/conf.d
      - ./certs:/etc/nginx/letsencrypt
      - /var/run/docker.sock:/tmp/docker.sock:ro
  redis:
    image: redis:latest
    ports:
      - "6379:6379"
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 10s
      retries: 3
      start_period: 30s
      timeout: 5s
  redis-commander:
    image: rediscommander/redis-commander:latest
    ports:
      - "8081:8081"
    environment:
      - REDIS_HOSTS=local:redis:6379
  adminer:
    image: adminer:latest
    ports:
      - "8080:8080"
    environment:
        ADMINER_DEFAULT_SEVERAL: db
  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./fastcgi-php.conf:/etc/nginx/snippets/fastcgi-php.conf
    depends_on:
      - "app"
volumes:
  db_data:
Automate Pull Request deployment using GitHub Actions and Docker. Use HNG project's pr-deploy GitHub Action:
Follow instructions from the https://github.com/hngprojects/pr-deploy to set up pull request deployments.
Ensure the action is configured to deploy previews for pull requests. In your GitHub Actions workflow, build Docker images for your application.
This workflow below will deploy on push or pull request.
- On push, it will build the image, Use 
scpto upload the built images to the server, thendocker loadthe image and run it using the appropriatedocker-compose file. 
name: PR and DevOps Deploy
on:
  pull_request:
    types: [opened, synchronize, reopened, closed]
  push:
    branches:
      - devops
jobs:
  build_and_deploy:
    if: github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v2
      - name: Build Docker Image
        run: |
          IMAGE_TAG="latest"
          docker buildx build --tag delve_be:${IMAGE_TAG} --file Dockerfile .
      - name: List Docker Images
        run: docker images
      - name: Save Docker Image
        run: |
          IMAGE_TAG="latest"
          docker save delve_be:${IMAGE_TAG} -o delve_be.tar
      - name: Upload Docker Image Artifact
        uses: actions/upload-artifact@v2
        with:
          name: docker-image
          path: delve_be.tar
  deploy_to_server:
    if: github.event_name == 'push'
    needs: build_and_deploy
    runs-on: ubuntu-latest
    steps:
      - name: Download Docker Image Artifact
        uses: actions/download-artifact@v2
        with:
          name: docker-image
          path: .
      - name: Transfer Docker Image to Server
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USER }}
          key: ${{ secrets.SSH_KEY }}
          source: delve_be.tar
          target: /tmp/php
      - name: Load and Deploy Docker Image on Server
        uses: appleboy/ssh-action@v0.1.6
        with:
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USER }}
          key: ${{ secrets.SSH_KEY }}
          script: |
            IMAGE_TAG="latest"
            cd /tmp/php
            docker load < delve_be.tar
            rm -f delve_be-${IMAGE_TAG}.tar
            cd /var/www/langlearnai-be/pr
            git pull origin devops
            docker-compose -f docker-compose.staging.yml down
            docker-compose -f docker-compose.staging.yml up -d
  deploy-pr:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Code
        uses: actions/checkout@v2
      - id: deploy
        name: Pull Request Deploy
        uses: hngprojects/pr-deploy@dev
        with:
          server_host: ${{ secrets.SSH_HOST }}
          server_username: ${{ secrets.SSH_USER }}
          server_password: ${{ secrets.SSH_PASSWORD }}
          comment: true
          context: '.'
          dockerfile: 'Dockerfile'
          exposed_port: '7001'
          github_token: ${{ secrets.TOKEN }}
      - name: Print Preview Url
        run: |
          echo "Preview Url: ${{ steps.deploy.outputs.preview-url }}" 
By following these steps, you will be able to Dockerize your applications and managing deployments across different environments using GitHub Actions.
Made with ❤️ by Olat-nji | Ujusophy | tulbadex | Darkk-kami | Otie16 courtesy of @HNG-Internship