Automate Deployment using CircleCI and Docker

Automate Deployment using CircleCI and Docker
Circleci
Nodejs
docker compose

Junius L

July 30, 2023

5 min read

Deploying applications manually can be time-consuming and error-prone. Automation is the key to streamlining the deployment process and ensuring consistency across different environments. In this blog post, we will walk you through the steps to automate your deployment using CircleCI and Docker, enabling you to deliver your application with ease and efficiency.

Install Docker

The first step is to install Docker on your target server, which will host your application. If you are using a RHEL-based VM/VPS, follow these commands to install Docker:

sudo dnf install -y dnf-utils zip unzip
sudo dnf config-manager --add-repo=https://download.docker.com/linux/centos/docker-ce.repo
sudo dnf remove -y runc
# install docker
sudo dnf install -y docker-ce --nobest # or sudo yum install -y docker

After installation, enable and start the Docker service:

sudo systemctl enable --now docker.service

Create a New User for Deployment

It's essential to create a separate user for deployment to enhance security and restrict access. Let's create a new user named circleci without password-based login:

sudo useradd -m -d /home/circleci -s /bin/bash circleci

Next, generate an SSH key for the "circleci" user to allow secure logins:

ssh-keygen -m PEM -t rsa -f .ssh/circleci

Now, create a .ssh directory for the circleci user

sudo mkdir /home/circleci/.ssh

add public key to authorized_keys inside /home/circleci/.ssh/

copy the public key from the following command

cat ~/.ssh/circleci.pub

and paste it in here

sudo vi /home/circleci/.ssh/authorized_keys

set the correct permissions:

sudo chown -R circleci:circleci /home/circleci

Configure Docker Commands for the Non-Root User

By default, Docker commands require root privileges. To allow the circleci user to use Docker without sudo, add the following lines to the sudoers file:

echo "circleci  ALL=(ALL)  NOPASSWD: /usr/bin/docker" | sudo tee -a /etc/sudoers
echo "alias docker=\"sudo /usr/bin/docker\"" | sudo tee -a /home/circleci/.bash_profile

Add SSH Key to CircleCI

For CircleCI to access your deployment server securely, you need to add the generated SSH key to CircleCI's SSH Keys settings. Run the following command to display the public key:

cat ~/.ssh/circleci

Copy the output, go to your CircleCI, select a project then click project settings, select "SSH Keys," and paste the private key in the private key text box.

Create the Deployment Script

Now, navigate to the /home/circleci directory on your server and create a deploy.sh file. This script will be executed by CircleCI whenever changes are pushed to GitHub:

cd /home/circleci
vi deploy.sh

Enter the following content in the deploy.sh file:

#!/bin/bash
# Runs docker compose
docker compose up --scale api=3 -d --build --force-recreate

Make this file an executable by running:

chmod +x deploy.sh

Create the Docker Compose Configuration

To define the services and configurations for your application, create a docker-compose.yml file:

vi docker-compose.yml

Paste the following content into the docker-compose.yml file:

version: "3.8"
services:
  api:
    restart: always
    build:
      context: https://${TOKEN}@github.com/julekgwa/cibe.git#main
      dockerfile: Dockerfile
    ports:
      - "8083-8085:8083"
    environment:
      MONGODB_URI: mongodb://db/movies
  db:
    restart: always
    image: mongo
    volumes:
      - movies:/data/db
 
volumes:
  movies:

Integrate Your GitHub Project with CircleCI

To automate builds and deployments triggered by GitHub commits, you need to integrate your GitHub repository with CircleCI. Follow the instructions in the CircleCI documentation to add your project to CircleCI.

Update the config.yml File in .circleci

The config.yml file in the .circleci directory defines your CircleCI pipeline. Update this file with the following content to execute the deployment script:

jobs:
  pull-and-build:
    docker:
      - image: arvindr226/alpine-ssh
    steps:
      - checkout
      - run: ssh -p $PORT -oStrictHostKeyChecking=no -v $USER@$IP "./deploy.sh"
 
# Orchestrate our job run sequence
workflows:
  version: 2
  build-project:
    jobs:
      - pull-and-build:
          filters:
            branches:
              only:
                - main

Adding an Nginx Proxy (Optional)

If you want to use an Nginx proxy to manage incoming traffic to your application, follow these steps:

First, install Nginx on your server:

sudo dnf install nginx
sudo systemctl enable --now nginx

Next, create an Nginx configuration file to proxy requests to your application:

sudo vi /etc/nginx/conf.d/myapp.conf

Add the following content to the configuration file:

upstream appservers {
  server 127.0.0.1:8083;
  server 127.0.0.1:8084;
  server 127.0.0.1:8085;
}
 
server {
  listen 80 default_server;
  listen [::]:80 default_server;
  server_name _;
  root /usr/share/nginx/html;
 
  location / {
    client_max_body_size 100M;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $http_host;
    proxy_pass http://appservers;
    proxy_redirect off;
  }
}

Troubleshooting Tips

If you encounter permission issues when running Docker Compose from CircleCI, you can fix the problem by changing the permissions for /var/run/docker.sock:

sudo chmod 666 /var/run/docker.sock

Congratulations! You've successfully automated the deployment process using CircleCI and Docker. With this setup, every time you push changes to your GitHub repository, CircleCI will build and deploy your application automatically. This ensures a seamless and consistent deployment workflow, making your development process smoother and more efficient. Happy coding!