<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Kipchirchir Langat Emmanuel</title>
    <description>The latest articles on DEV Community by Kipchirchir Langat Emmanuel (@langatmanuk).</description>
    <link>https://dev.to/langatmanuk</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F916861%2Fd266ec50-3bb8-45f7-91ff-252d1c62614d.jpg</url>
      <title>DEV Community: Kipchirchir Langat Emmanuel</title>
      <link>https://dev.to/langatmanuk</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/langatmanuk"/>
    <language>en</language>
    <item>
      <title>Django automated deployments to Digital ocean using GitHub actions</title>
      <dc:creator>Kipchirchir Langat Emmanuel</dc:creator>
      <pubDate>Fri, 13 Jan 2023 18:16:34 +0000</pubDate>
      <link>https://dev.to/langatmanuk/django-automated-deployments-to-digital-ocean-using-github-actions-53jf</link>
      <guid>https://dev.to/langatmanuk/django-automated-deployments-to-digital-ocean-using-github-actions-53jf</guid>
      <description>&lt;p&gt;In this article, you will learn how to build an automated GitHub actions pipeline that deploys a Django application to a digital ocean droplet.&lt;/p&gt;

&lt;p&gt;Prerequisites:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A GitHub account.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A docker hub account.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A digital ocean account.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  1 Base application.
&lt;/h4&gt;

&lt;h4&gt;
  
  
  For this guide, we shall be using a base project that can be &lt;a href="https://github.com/manulangat1/github-actions-do-article.git" rel="noopener noreferrer"&gt;cloned here&lt;/a&gt;.
&lt;/h4&gt;

&lt;p&gt;Navigate to your desired folder/directory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd Desktop

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clone the project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/manulangat1/github-actions-do-article.git

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create and activate a virtual environment (use whatever tool you are comfortable with to achieve this.)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 -m virtualenv venv 
source venv/bin/activate
#install the required dependancies 
pip install -r requirements.txt

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the Django development server to confirm that all is well.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 manage.py runserver

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Setting up the GitHub actions file.
&lt;/h4&gt;

&lt;p&gt;On the root of the project create a folder &lt;code&gt;.github&lt;/code&gt;, and inside it create another folder named workflows and a file inside the workflows folder named integrations.yaml. The structure should be as illustrated in the image below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnr5rhp0xs7hwqrib0dd3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnr5rhp0xs7hwqrib0dd3.png" width="480" height="337"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Paste the following code into the &lt;code&gt;intergrations.yaml&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Continuous Integration and Delivery # workflow name

on: # this is the entry point to the events, we specificy when the actions should be run
  push:
    branches: [develop] #specificy which branch should the workflow be triggered
  pull_request:
    branches: [develop] #specificy which branch should the workflow be triggered

jobs:
  testing-docker-compose-auto-deploy-digital-ocean: # name of the job 
    runs-on: ubuntu-latest # specify that the app will run on the latest version of ubuntu
    steps: # steps that should be followed while building and deploying the image.
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v2
      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2
      - uses: actions/checkout@v2

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Dockerize the application.
&lt;/h4&gt;

&lt;p&gt;Create a new file named &lt;code&gt;Dockerfile&lt;/code&gt; at the root of the project and paste the following lines of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
# FROM python:3.9.6-alpine 
FROM python:3.10.1-slim-buster 

# WORKDIR 
ENV APP_HOME=/app
RUN mkdir $APP_HOME
RUN mkdir $APP_HOME/staticfiles
WORKDIR $APP_HOME

LABEL maintainer='manulangat1'

LABEL description="This is an application that shows how to create an automatic ci pipepline that deploys the django app to a digital ocean droplet" 

ENV PYTHONDONTWRITEBYTECODE=1

ENV PYTHONUNBUFFERED=1  

ENV DEBUG=False

ENV ENVIRONMENT=staging

RUN apt-get update \
    &amp;amp;&amp;amp; apt-get install -y build-essential \
    &amp;amp;&amp;amp; apt-get install -y libpq-dev \
    &amp;amp;&amp;amp; apt-get install -y gettext \
    &amp;amp;&amp;amp; apt-get -y install netcat gcc postgresql \
    &amp;amp;&amp;amp; apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
    &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*

RUN pip3 install --upgrade pip 

COPY requirements.txt $APP_HOME/requirements.txt 

COPY . $APP_HOME/
RUN pip3 install -r $APP_HOME/requirements.txt 

COPY /entrypoint /entrypoint
RUN sed -i 's/\r$//g' /entrypoint
RUN chmod +x /entrypoint

ENTRYPOINT ["/entrypoint"]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once done, create a new file &lt;code&gt;docker-compose.yaml&lt;/code&gt; and paste the following lines of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3.8'

services:
  web:
    build: 
      context: .
      dockerfile: Dockerfile
    command: gunicorn do-guide.wsgi:application --bind 0.0.0.0:8000
    volumes:
      - static_volume:/home/app/web/staticfiles

    image: manulangat/auto-deploy-do-github-actions:latest
    ports:
      - "8000:8000"
    networks:
      - bms_staging

volumes:
  static_volume:

networks:
  bms_staging:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this in place, you can now add the steps to build the docker images in the GitHub actions workflow file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      - uses: actions/checkout@v2
      - name: Build the stack
        run: docker-compose -f docker-compose.yaml up -d --build

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4 Deploy to Dockerhub.
&lt;/h4&gt;

&lt;p&gt;We want the latest image to be deployed to docker hub, Login to your docker hub account and create a new repository.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr62t11vxy6uc7y1vbro2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fr62t11vxy6uc7y1vbro2.png" width="800" height="371"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Grab the image name eg manulangat/auto-deploy-do-github-actions:tagname and head over to the workflow file.&lt;/p&gt;

&lt;p&gt;In the workflow file, add a step that logins it to docker hub using your username and password, add these as repository secrets on GitHub&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwt3ccaupukmj66hu7gyv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwt3ccaupukmj66hu7gyv.png" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once done with that, head over to the workflow file and add a step that login into Dockerhub.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: Login to DockerHub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The workflow file should at this point resemble the one below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Continuous Integration and Delivery

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

jobs:
  testing-docker-compose:
    runs-on: ubuntu-latest
    steps:
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v2

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2

      - uses: actions/checkout@v2
      - name: Build the stack
        run: docker-compose -f docker-compose.yaml up -d --build

      - name: Get docker logs
        run: docker ps

      - name: Login to DockerHub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, the step that pushed the built docker image can now be added after the login to Dockerhub step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: Push to dockerhub
        run: |
          docker-compose push # this pushes the image to the repo that we have defined in the docker-compose.yaml file.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a step that stops the containers&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: stop containers
        run: docker-compose -f docker-compose.yaml down --volumes

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  5. Auto-deploy to digital ocean droplet.
&lt;/h4&gt;

&lt;p&gt;Head over to the digital ocean page and log in, upon logging in, create a &lt;a href="https://marketplace.digitalocean.com/apps/docker" rel="noopener noreferrer"&gt;Docker droplet&lt;/a&gt;, for this tutorial, a shared CPU of 2Gb and 50Gb SSD disk is sufficient. Give the droplet whatever name you see fit and hit the create droplet button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwmkkdxjjxioaf019fqur.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwmkkdxjjxioaf019fqur.png" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6kzcd4iza6lkolqktde.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6kzcd4iza6lkolqktde.png" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To configure firewalls and enable port 8000 and port 7000, which our Django app will be using communicate with the outside world, go to the networking tab, then the firewall option. This will redirect you to the page below, fill name, add a custom TCP inbound rule to port 8000 and 7000, attach it to the droplet created above and hit create firewall button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5wvtxihh758oxylwapmb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5wvtxihh758oxylwapmb.png" width="800" height="412"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With the droplet and firewall now up and running, you can now add a step that automatically deploys the django app to the digital ocean droplets, but before that you need to add a few secrets on github repo.&lt;/p&gt;

&lt;p&gt;Ssh into your digital ocean droplet&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh root@YOUR_DO_IP

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the following command to generate a new ssh key pair that the pipeline will use to connect to the droplet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh-keygen

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the value of the generated private key navigate to the ssh folder by&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ~/.ssh

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the private key, run the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat id_rsa

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;make sure that you copy the whole of the contents and add it to your repository secrets as &lt;code&gt;DO_PRIVATE_KEY&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With that in place, copy the public key&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat id_rsa.pub

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and add it to the authorised_keys file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nano authorised_keys

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;paste the contents and save and close the file.&lt;/p&gt;

&lt;p&gt;Go back to the root of the project and create a new folder &lt;code&gt;django-ci-example&lt;/code&gt;, create a .env file if need be and a 'docker-compose.yaml' file and paste into it the contents of the file into.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nano docker-compose.yaml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And paste in the following lines of code&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;version: '3.8'

services:
  web:
    build: 
      context: .
      dockerfile: Dockerfile
    command: gunicorn do-guide.wsgi:application --bind 0.0.0.0:8000
    volumes:
      - static_volume:/home/app/web/staticfiles

    image: manulangat/auto-deploy-do-github-actions:latest
    ports:
      - "8000:8000"
    networks:
      - django-ci-example

volumes:
  static_volume:

networks:
  django-ci-example:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Head over to your workflow file and add the following step&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;- name: Executing remote command and deployment to digital ocean for dev enviroment
        uses: appleboy/ssh-action@master
        with:
          host: "YOUR_DO_IP"
          USERNAME: "root"
          PORT: 22
          KEY: ${{ secrets.DO_PRIVATE_KEY}}
          script: |
            cd django-ci-example/
            docker system prune -af
            docker compose -f docker-compose.staging.yaml down --volumes
            echo "${{secrets.DOCKER_PASSWORD}}" | docker login -u ${{secrets.DOCKER_USERNAME}} --password-stdin
            docker system prune -af
            docker compose -f docker-compose.staging.yaml pull
            docker compose -f docker-compose.staging.yaml up --build --remove-orphans -d --force-recreate
            # docker-compose -f docker-compose.staging.yaml up --build -d

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, your actions file should be similar to the one below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;name: Continuous Integration and Delivery

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main, develop]

jobs:
  testing-docker-compose:
    runs-on: ubuntu-latest
    steps:
      - name: Set up QEMU
        uses: docker/setup-qemu-action@v2

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v2

      - uses: actions/checkout@v2
      - name: Build the stack
        run: docker-compose -f docker-compose.yaml up -d --build

      - name: Get docker logs
        run: docker ps

      - name: Login to DockerHub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Push to dockerhub
        run: |
          docker-compose push

      - name: stop containers
        run: docker-compose -f docker-compose.yaml down --volumes

      - name: Executing remote command and deployment to digital ocean for dev enviroment
        uses: appleboy/ssh-action@master
        with:
          host: "YOUR_DO_IP"
          USERNAME: "root"
          PORT: 22
          KEY: ${{ secrets.DO_PRIVATE_KEY}}
          script: |
            cd django-ci-example/
            docker system prune -af
            docker compose -f docker-compose.staging.yaml down --volumes
            echo "${{secrets.DOCKER_PASSWORD}}" | docker login -u ${{secrets.DOCKER_USERNAME}} --password-stdin
            docker system prune -af
            docker compose -f docker-compose.staging.yaml pull
            docker compose -f docker-compose.staging.yaml up --build --remove-orphans -d --force-recreate
            # docker-compose -f docker-compose.staging.yaml up --build -d

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test this out, make commit and push your works and the actions should be triggered. Once the actions is done, navigate to the web page ie &lt;code&gt;YOUR_DO_IP:7000&lt;/code&gt; and you should be welcomed with a page as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4kv13c7s1f92345p198v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4kv13c7s1f92345p198v.png" width="800" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code for this project can be found at this GitHub &lt;a href="https://github.com/manulangat1/github-actions-do-article" rel="noopener noreferrer"&gt;repo&lt;/a&gt; .&lt;/p&gt;

&lt;p&gt;Kindly follow me to get instant notifications whenever I post articles and guides on Devops and Django.&lt;/p&gt;

&lt;p&gt;Happy hacking.&lt;/p&gt;

</description>
      <category>discuss</category>
    </item>
    <item>
      <title>Deploying Django using Kubernetes - a gentle intro.</title>
      <dc:creator>Kipchirchir Langat Emmanuel</dc:creator>
      <pubDate>Sun, 18 Dec 2022 09:47:42 +0000</pubDate>
      <link>https://dev.to/langatmanuk/deploying-django-using-kubernetes-a-gentle-intro-5fj8</link>
      <guid>https://dev.to/langatmanuk/deploying-django-using-kubernetes-a-gentle-intro-5fj8</guid>
      <description>&lt;h4&gt;
  
  
  1. What is Kubernetes?
&lt;/h4&gt;

&lt;p&gt;Kubernetes is an open-source container orchestration tool developed by Google. Kubernetes offers the following features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;High availability&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Scalability or high performance.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Disaster recovery (backups and restore)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To get an in-depth read of what Kubernetes is and the problem it solves, read the &lt;a href="https://kubernetes.io/"&gt;official guide&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To install Kubernetes in your preferred operating system, follow the guides on the&lt;/p&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/docs/home/"&gt;official&lt;/a&gt; documentation&lt;/p&gt;

&lt;h4&gt;
  
  
  2. A brief intro to services will be covered in this article.
&lt;/h4&gt;

&lt;p&gt;In this article, you will learn about the following Kubernetes components:&lt;/p&gt;

&lt;h5&gt;
  
  
  2.1 Pods.
&lt;/h5&gt;

&lt;p&gt;A pod is the smallest unit of Kubernetes. It provides an abstraction over a container and helps you to interact only with the Kubernetes layer and is usually meant to run one container per pod this is because the pods are scaled up and down as a single unit regardless of a container need thus resulting in expensive cloud costs.&lt;/p&gt;

&lt;p&gt;Each pod gets allocated an IP address upon creation and they use the IP address to communicate. Pods are ephemeral and can die easily thus the need for services&lt;/p&gt;

&lt;h5&gt;
  
  
  2.2 Services and Ingress.
&lt;/h5&gt;

&lt;p&gt;A service is a static IP address that can be attached to the pods and is not connected to the lifecycle of a Pod thus when a pod dies and is recreated. There are various types of services namely:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;ClusterIP service - is the default type of service and is used to expose a service on an Ip internal to the cluster. Access is only permitted to objects with the cluster.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;HeadlessIp Service&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Nodeport Service&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;LoadBalancer Service&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ingress -&lt;/p&gt;

&lt;h5&gt;
  
  
  2.3 ConfigMaps and Secrets.
&lt;/h5&gt;

&lt;p&gt;ConfigMap contains the external configuration of your application both are local volumes but are rather own components.&lt;/p&gt;

&lt;p&gt;Secret - used to store credentials and it is stored in base64 format. used for individual key-value pairs or for mounting files.&lt;/p&gt;

&lt;h6&gt;
  
  
  2.4 Deployments.
&lt;/h6&gt;

&lt;p&gt;Is an abstraction over the pod's blueprint for creating pods. In practice, you will be creating deployments and not pods since it provides an avenue to scale up and down.&lt;/p&gt;

&lt;h5&gt;
  
  
  2.5 Volumes.
&lt;/h5&gt;

&lt;p&gt;It is useful when persisting data in k8s for pod restart and does not depend on the pod lifecycle Should be available on all nodes. Highly available that survives even if cluster crashes&lt;/p&gt;

&lt;p&gt;My SQL - data gets added, updated but once you restart a pod the data goes as k8s and does not&lt;/p&gt;

&lt;p&gt;We will briefly cover the 3 classes of Kubernetes volumes&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Persistent Volume&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;a cluster resource&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;created via a YAML file.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Takes storage from physical storage eg local storage, NFS server etc&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;decide what type and manage them eg backups etc&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;They are not namespaced. local vs remote volume types: local volume violates&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;being tied to 1 specific node.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;surviving cluster crashes&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For DB persistence, always use remote storage.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Persistent Volume Claim.&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Admin configures storages (create and configure).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Admin creates PV from these storage backends.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;App claim volumes and also created using YAML files. must exist in the same ns as the PVC&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;do not care where your storage is,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Easier for developers.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pod -&amp;gt; PVC -&amp;gt; CLaim&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Storage class. provisions persistent volumes dynamically whenever PVC claims it. created via a YAML class claimed by PVC - add a storage class Name&lt;/li&gt;
&lt;/ol&gt;

&lt;h5&gt;
  
  
  2.6 Namespaces.
&lt;/h5&gt;

&lt;p&gt;Namespaces can be thought of as a virtual cluster inside a cluster. It is used to isolate resources/ clusters together.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It is important to note that you cannot access most of the resources from another namespace eg if you have a config map in project A ns, you cannot use that configmap in project B namespace but instead, you have to create the same in the other project. However, a service can be referenced in another project. To get a list of all components that can be namespace run
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl api-resources --name-spaced=true

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Volumes are accessible throughout the cluster To get a list of all non-namespaces components run
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl api-resources --name-spaced=false

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This brings up the question, why use namespaces?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Group resources into namespaces eg DB ns, monitoring ns, Nginx ingress ns&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Many teams are using the same application - one team can easily overwrite another team's work. Each team can work independently&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Resource sharing - staging and development environments.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;When you use blue-green deployment for your application.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Access and Resource limits on Namespaces, 2 teams - give the team access to their own ns and define resource quotas.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By default, K8s has the following namespaces defined.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Kubernetes-dashboard - This &lt;code&gt;ns&lt;/code&gt; is shipped only with minikube and you will not have this in a normal cluster.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;kube-system - Not meant for your use. Components deployed here include the system processes,&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Kube-public - Has a config map that contains cluster information and which is accessible without auth. Type &lt;code&gt;kubectl cluster info&lt;/code&gt; on your terminal and you should see info about your minikube installation.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;kube-node-list - Holds info about the heartbeats of every node and determines the availability of nodes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Default namespace - Used to create a new namespace at the beginning.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To get a list of all the namespaces run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get namespace

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use a CLI command as shown below or via a namespace configuration file.&lt;/p&gt;

&lt;p&gt;Via a CLI(command line ) command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; kubectl create namespace my-namespace

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And you can now assign the created namespace to a Kubernetes namespace as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1 
kind: ConfigMap 
metadata:
  name: my-configmap
  name: my-namspace

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To switch over your namespaces, install kubens as detailed in this GitHub&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/ahmetb/kubectx"&gt;repository&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  2.6 Sample YAML configuration file.
&lt;/h5&gt;

&lt;p&gt;In this part, you will learn the basic syntax of a Kubernetes YAML file and how it is usually structured.&lt;/p&gt;

&lt;p&gt;The main parts of a YAML file include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Metadata. - Contains the metadata of the file eg name and others such as labels.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Specification - specific to the kind you are creating.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Status- automatically generated and added by K8s. This is the basis of the self-healing nature of k8s eg you have specified you need 2 replicas and if one dies, it will look at the status for the desired state and spin up a new pod.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Attached below is a simple k8s YAML file of kind Deployment&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: name-of-deployment
  labels:
    app: name #should be the same with labels in the template
spec:
  replicas: 2
  selector:
    matchLabels:
      app: name
  template: # blue print of a pod
    metadata:
      labels:
        app: name
    spec:
      containers:
        - name: container-name
          image: image-name-ref
          imagePullPolicy: Always

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Django app that will be used (Optional).
&lt;/h4&gt;

&lt;h5&gt;
  
  
  For the demonstration, the following application will be used
&lt;/h5&gt;

&lt;h5&gt;
  
  
  &lt;a href="https://github.com/manulangat1/ecomerce-monolith.git"&gt;ecommerce monolith&lt;/a&gt;. Navigate to your desired folder ie
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd Desktop

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clone the application by using the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone https://github.com/manulangat1/ecomerce-monolith.git

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the cloning is done navigate into the cloned directory and change into a new branch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git switch -f "feat-h8s-test-your-name"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;N/B. This step is optional and you can use any of your code repositories to follow along with this tutorial.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Deployments and services set up.
&lt;/h4&gt;

&lt;h5&gt;
  
  
  4.1 Deployment file
&lt;/h5&gt;

&lt;p&gt;On the root of your project, create a folder named k8s and navigate inside the newly created folder&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkidr k8s

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate into the created k8s folder&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd k8s

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a file named django-deployment.yaml&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch django-deployment.yaml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once created, add the following lines of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: django-be-deployment
  labels:
    app: django-be #should be same with labels in template
spec:
  replicas: 1
  selector:
    matchLabels:
      app: django-be
  template: # blue print of a pod
    metadata:
      labels:
        app: django-be
    spec:
      containers:
        - name: django-be
          image: manulangat/django-ecomerce-monolith
          imagePullPolicy: Always
          command: ["gunicorn"]
          args: ["--bind=localhost:8000","monolithEcommerce.wsgi:application"]
          ports:
            - containerPort: 8000

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the following command at the project root to apply the changes we have added.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f django-deployment.yaml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To get the pod details of the app and to get the progress, run the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get pod | grep django

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It should have a similar output as the one shown below, kindly note that the container creation process may take some bit of time when the command is run initially.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DM65sg0Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1671014374526/fkwaEkn_r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DM65sg0Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1671014374526/fkwaEkn_r.png" alt="" width="880" height="31"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To get the logs of the deployment created initially run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl logs -f deployment/django-deployment

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the output should be similar to the image shown below if you are using the base project shared above.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2FEJueVb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1671014507054/NIJUvUqij.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2FEJueVb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1671014507054/NIJUvUqij.png" alt="" width="880" height="58"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  4.2 Secrets set up.
&lt;/h5&gt;

&lt;p&gt;Now that our deployment service is up and running, we may need to pass some environment variables such as the Django-secret key that should be hidden from the public, this is better done through the use of secrets and thus the need for the secrets file. Note that values stored in Secretes should be base64 encoded&lt;/p&gt;

&lt;p&gt;While on the project root, create a new file inside the k8s folder by&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd k8s 
touch django-secrets.yaml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once that is done, add the following lines of YAML code into the newly created &lt;code&gt;django-secrets.yaml&lt;/code&gt; file. To get a base64 encoded value of your secret run the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;echo -n "YOUR_SECRET_KEY" | base64


apiVersion: v1
kind: Secret
metadata:
  name: django-secrets
type: Opaque
data:
  DJANGO_SITE_SECRET_KEY: WU9VUl9TRUNSRVRfS0VZ

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To apply and create the secret, run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl apply -f k8s/django-secrets.yaml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To confirm whether the secret was created successfully, use the below command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get secrets | grep django

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and the output should be similar to the image attached below&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1YP5EBGY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1671016213587/WxQzZPjZZ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1YP5EBGY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1671016213587/WxQzZPjZZ.png" alt="" width="880" height="58"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The next step is now accessing the secrets in our django deployment file. Head over to the &lt;code&gt;k8s/django-deployment.yaml&lt;/code&gt; file and below the ports option add the following configurations to load the secret and access the value for the key DJANGO_SECRET_SITE_KEY.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;env:
            - name: DJANGO_SITE_SECRET_KEY
              valueFrom:
                secretKeyRef:
                  name: django-secrets # name given to the secret in django-secrets.yaml file
                  key: DJANGO_SITE_SECRET_KEY

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this stage, your &lt;code&gt;django-deployment.yaml&lt;/code&gt; the file should resemble this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: apps/v1
kind: Deployment
metadata:
  name: django-be-deployment
  labels:
    app: django-be #should be same with labels in template
spec:
  replicas: 1
  selector:
    matchLabels:
      app: django-be
  template: # blue print of a pod
    metadata:
      labels:
        app: django-be
    spec:
      containers:
        - name: django-be
          image: &amp;lt;REF_OF_YOUR_IMAGE&amp;gt;
          imagePullPolicy: Always
          command: ["gunicorn"]
          args: ["--bind=localhost:8000", "monolithEcommerce.wsgi:application"] # replace monolithEcommerce with the name of your
          ports:
            - containerPort: 8000
          env:
            - name: DJANGO_SITE_SECRET_KEY
              valueFrom:
                secretKeyRef:
                  name: django-secrets # name given to the secret in django-secrets.yaml file
                  key: DJANGO_SITE_SECRET_KEY

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this stage, we have gone through Kubernetes deployments and secrets and tested it out via kubectl commands all is well, in the next step, we shall learn how to expose our application to the outside world through Kubernetes services.&lt;/p&gt;

&lt;h5&gt;
  
  
  4.3 Services- Exposing our django app to the outside world.
&lt;/h5&gt;

&lt;p&gt;Create a new file in the k8s folder ie&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch k8s/django-service.yaml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And add the following pieces of yaml code inside it&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
apiVersion: v1
kind: Service
metadata:
  name: django-service
spec:
  selector:
    app: django-be # name of app as defined in the 
  type: LoadBalancer # specifies the type of service created. 
  ports:
    - protocol: TCP
      port: 1338
      targetPort: 8000
      nodePort: 30001

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the commands below to apply our changes and to confirm whether everything works as expected. The output of the second command should be similar to the image attached below&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ur3aW1yl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1671023133219/a09TYjUX0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ur3aW1yl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1671023133219/a09TYjUX0.png" alt="" width="880" height="44"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The service can now be exposed via &lt;code&gt;minikube tunnel command&lt;/code&gt;. Head to your terminal and paste in the following :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube tunnel NAME_OF_YOUR_SERVICE

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It will prompt you to input your password and once done, it will show the logs similar to the one in the picture attached below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HBbeQeNE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1671356775778/e-MbB8MZU.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HBbeQeNE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1671356775778/e-MbB8MZU.png" alt="" width="880" height="316"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To access the application, get the IP address stated above and navigate to it ie&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;192.168.49.2:30000/

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this article, we have gone through the basics of Kubernetes and how to use components such as Deployments, services and secrets in our Django app. In the next article in this series, you will learn about using volumes, exposing our app using ingress and deploying it to a digital ocean-managed Kubernetes service.&lt;/p&gt;

&lt;p&gt;Happy hacking!!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Create and use custom Django signals by building a blog application</title>
      <dc:creator>Kipchirchir Langat Emmanuel</dc:creator>
      <pubDate>Wed, 19 Oct 2022 19:11:16 +0000</pubDate>
      <link>https://dev.to/langatmanuk/create-and-use-custom-django-signals-by-building-a-blog-application-3d2l</link>
      <guid>https://dev.to/langatmanuk/create-and-use-custom-django-signals-by-building-a-blog-application-3d2l</guid>
      <description>&lt;p&gt;In this article, you will learn how to create and use custom Django signals. Then use them to log all actions undertaken by a user on the application&lt;/p&gt;

&lt;h4&gt;
  
  
  1. What are Django signals?
&lt;/h4&gt;

&lt;p&gt;According to the Django documentation, a signal is &lt;code&gt;In a nutshell, signals allow certain senders to notify a set of receivers that some action has taken place. Theyre especially useful when many pieces of code may be interested in the same events.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;There are various built-in signals that you can read comprehensively &lt;a href="https://docs.djangoproject.com/en/4.1/topics/signals/"&gt;here&lt;/a&gt;. However, for the scope of this project, you shall learn about creating custom signals.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Set up a new Django project.
&lt;/h4&gt;

&lt;h5&gt;
  
  
  2.1 Navigate into your desired folder and create a virtual environment.
&lt;/h5&gt;

&lt;p&gt;Navigate to your desired folder, e.g Downloads and create and activate a virtual environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd Desktop

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;create a folder that will house the Django project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir audit-logs-app &amp;amp;&amp;amp; cd audit-logs-app

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;create and activate a virtual environment&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 -m virtualenv venv

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Activate the virtual environment&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;source venv/bin/activate # if you are using a Linux distro 
.\venv\Scripts\activate # if running on windows

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  2.2 Install Django and create project
&lt;/h5&gt;

&lt;p&gt;You can now install Django&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install django

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a new Django project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;django-admin startproject djangoauditlog

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate into the django project. This is where we will create our apps and write the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd djangoauditlog

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Create django apps (authentication and posts)
&lt;/h4&gt;

&lt;h5&gt;
  
  
  3.1 Create an authentication app and install drf and django-rest-knox
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;django-admin startapp authentication

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Head over to your &lt;code&gt;settings.py&lt;/code&gt; file and add the &lt;code&gt;authentication&lt;/code&gt; app to the list of &lt;code&gt;INSTALLED_APPS&lt;/code&gt; as shown below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--btdhJZBG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1665307131180/BtNd1TQWB.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--btdhJZBG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1665307131180/BtNd1TQWB.png" alt="Screenshot from 2022-10-09 12-18-40.png" width="480" height="199"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that is done install django rest framework and django-rest-knox by&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pip install djangorestframework django-rest-knox

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a successful installation head over to your &lt;code&gt;settings.py&lt;/code&gt; file and add the &lt;code&gt;rest_framework&lt;/code&gt; and &lt;code&gt;knox&lt;/code&gt; to the list of &lt;code&gt;INSTALLED_APPS&lt;/code&gt; as shown below.&lt;/p&gt;

&lt;p&gt;Still on the &lt;code&gt;settings.py&lt;/code&gt; file, add the following lines of code which tells rest_framework the authentication classes that is should use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;REST_FRAMEWORK = {
    "DEFAULT_AUTHENTICATION_CLASSES": (
        "knox.auth.TokenAuthentication",
        "rest_framework.authentication.TokenAuthentication",
        "rest_framework.authentication.SessionAuthentication",
        "rest_framework.authentication.BasicAuthentication",
    ),
    # 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  3.2 Create a custom User model.
&lt;/h5&gt;

&lt;p&gt;We will create a custom user model using the &lt;code&gt;AbstractUser&lt;/code&gt; abstract class. Head to the &lt;code&gt;apps/authentication/models.py&lt;/code&gt; and add the following code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.db import models
from django.contrib.auth.models import AbstractUser
from django.utils import translation

#local imports 
#from apps.common.models import TimeStampedModel
# Create your models here.

class User(AbstractUser):
    bio = models.TextField(verbose_name='user bio', null=True, blank=True)

    def __str__ (self) -&amp;gt; str:
        return self.email

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  3.3 Create your auth serializer files.
&lt;/h5&gt;

&lt;p&gt;Head over to the &lt;code&gt;apps/authentication/serializers.py&lt;/code&gt; file and add the following lines of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from rest_framework import serializers 

#django imports 
from django.contrib.auth import get_user_model, authenticate
#local imports
from apps.authentication.models import Profile

# instantiate our user model 
User = get_user_model()

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = ( 
            "id",
            "username",
            "email",
            "first_name",
            "last_name"
        )

class ProfileSerializer(serializers.ModelSerializer):
    username = serializers.CharField(source="user.username")
    class Meta:
        model = Profile 
        fields = ( 
            "username",
            "city",
            "state",
            "country"
        )

class RegisterSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id', 'username', 'email', 'password')
        extra_kwargs = {'password': {'write_only': True}}

    def create(self, validated_data):
        user = User.objects.create_user(validated_data['username'], validated_data['email'], validated_data['password'])
        return user

class LoginSerializer(serializers.Serializer):
    username = serializers.CharField()
    password = serializers.CharField()

    def validate(self, data):
        user = authenticate(**data)
        if user and user.is_active:
            return user
        raise serializers.ValidationError('Incorrect Credentials Passed.')

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  3.4 Create auth API endpoints.
&lt;/h5&gt;

&lt;p&gt;Head over to the &lt;code&gt;apps/authentication/views.py&lt;/code&gt; file and add the following lines of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.shortcuts import render
from rest_framework import views, generics, permissions, status
from rest_framework.response import Response

#local imports
from apps.authentication.serializers import UserSerializer, RegisterSerializer, LoginSerializer

from apps.authentication.exceptions import ProfileNotFound
# third party imports
from knox.models import AuthToken

# Create your views here.

class RegisterAPI(generics.GenericAPIView):
    serializer_class = RegisterSerializer
    def post(self, request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.save()
        print(user)
        user.save()
        token = AuthToken.objects.create(user)
        return Response({
            "users": UserSerializer(user, context=self.get_serializer_context()).data,
            "token": token[1]
        }, status=status.HTTP_200_OK)

class LoginAPI(generics.GenericAPIView):
    serializer_class = LoginSerializer

    def post(self,request):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data
        token = AuthToken.objects.create(user)
        return Response({
            "users": UserSerializer(user, context=self.get_serializer_context()).data,
            "token": token[1]
        }, status=status.HTTP_200_OK)

class UserAPI(generics.GenericAPIView):
    serializer_class = UserSerializer
    permission_classes = ( 
        permissions.IsAuthenticated,
    )
    def get(self,request):
        user = self.request.user 
        serializer = UserSerializer(user)
        return Response(serializer.data, status=status.HTTP_200_OK)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  3.5 Create the authentication URLs.
&lt;/h5&gt;

&lt;p&gt;Head over to the &lt;code&gt;apps/authentication&lt;/code&gt; folder and create a &lt;code&gt;urls.py&lt;/code&gt; file if it did not exists. After successful creation, paste in the following lines of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.urls import path 
from . import views
urlpatterns = [ 
    path('auth/register/', views.RegisterAPI.as_view(), name="registration_api"),
    path('auth/login/', views.LoginAPI.as_view(), name="login_api"),
    path('auth/me/', views.UserAPI.as_view(), name="get_logged_in_user_api"),
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  3.6 Testing out the authentication APIs
&lt;/h5&gt;

&lt;p&gt;Head over to postman or the tool you use and test out the APIs one by one and confirm that all are working fine. Feel free to tweak the code as you wish to achieve your desired functionality.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Create the blog application and the custom signal.
&lt;/h4&gt;

&lt;h5&gt;
  
  
  4.1 Create the blog application using django-admin command.
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;django-admin startapp blog

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Register the application in the installed apps in the &lt;code&gt;INSTALLED_APPS&lt;/code&gt; section in your settings.py file.&lt;/p&gt;

&lt;h5&gt;
  
  
  4.2 Create the blog models.
&lt;/h5&gt;

&lt;p&gt;Head over to your &lt;code&gt;blog/models.py&lt;/code&gt; file and paste in the following lines of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
from django.db import models
from django.contrib.auth import get_user_model

import uuid

# Create your models here.

User = get_user_model()

class TimeStampedUUIDModel(models.Model):
    pkid = models.BigAutoField(primary_key=True, editable=False)
    id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        abstract = True

class Tag(TimeStampedUUIDModel):
    title = models.CharField(max_length=199)

    def __str__ (self) -&amp;gt; str:
        return self.title

class Post(TimeStampedUUIDModel):
    user = models.ForeignKey(User, related_name="posts",
                             on_delete=models.CASCADE)
    title = models.CharField(max_length=199)
    content = models.TextField()
    tags = models.ManyToManyField(Tag)
    isPublished = models.BooleanField(default=False)
    image = models.CharField(max_length=255, null=True)
    slug = models.CharField(max_length=255, null=True)

    def __str__ (self) -&amp;gt; str:
        return self.title

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now run your migrations by heading over to your terminal and using the commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 manage.py makemigrations
python3 manage.py migrate

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  4.3 Create the posts serializer.
&lt;/h5&gt;

&lt;p&gt;At this point, you will handle the serializer classes that will help in converting the queryset objects to a JSON readable format.&lt;/p&gt;

&lt;p&gt;Head over to &lt;code&gt;blogs/serializers.py&lt;/code&gt; and paste in the following lines of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from rest_framework import serializers
from .models import Post, Tag

class TagSerializer(serializers.ModelSerializer):
    class Meta:
        model = Tag
        fields = (
            "id",
            "title",
        )

class PostSerializer(serializers.ModelSerializer):
    class Meta:
        model = Post
        fields = (
            "id",
            "title",
            "content",
        )

class PostDetailSerializer(serializers.ModelSerializer):
    tags = serializers.SerializerMethodField()

    class Meta:
        model = Post
        fields = ("id", "title", "content", "tags")

    def get_tags(self, obj):
        return TagSerializer(obj.tags.all(), many=True).data

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  4.4 Blog application API endpoints. Create the views.
&lt;/h5&gt;

&lt;p&gt;You will now create API endpoints, using django rest framework that will be used to communicate with the models (CRUD operations). Head over to the &lt;code&gt;blogs/views.py&lt;/code&gt; file and paste in the following lines of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
from rest_framework import permissions, status, generics
from rest_framework.views import APIView
from rest_framework.response import Response

import requests
# Create your views here.

from .models import Post, Tag
from .serializers import TagSerializer, PostDetailSerializer, PostSerializer

class TagAPI(generics.ListCreateAPIView):
    serializer_class = TagSerializer
    queryset = Tag.objects.all().order_by("-created_at")
    permission_classes = [permissions.IsAuthenticated]

class PostAPI(generics.ListCreateAPIView):
    serializer_class = PostSerializer
    queryset = Post.objects.all().order_by("-created_at")
    permission_classes = (permissions.IsAuthenticated,)

    def perform_create(self, serializer):
        data = self.request.data
        new_post = serializer.save(
            user=self.request.user, title=data["title"], content=data["content"]
        )
        all_posts = Post.objects.all().order_by("-created_at")
        serializer = PostSerializer(all_posts, many=True)
        return Response(serializer.data, status=status.HTTP_201_CREATED)

class PostDetailAPI(APIView):
    def get(self, request, id):
        post = get_post(id)
        serializer = PostDetailSerializer(post)
        return Response(serializer.data, status=status.HTTP_200_OK)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the views now in place, go ahead and create a new file &lt;code&gt;blogs/urls.py&lt;/code&gt; and add the following lines of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;from django.urls import path
from . import views

urlpatterns = [
    path("v1/posts/", views.PostAPI.as_view(), name="get_a_list_of_all_blogs"),
    path("v1/tags/", views.TagAPI.as_view(), name="get_all_tags"),
    path("v1/posts/&amp;lt;str:id&amp;gt;/", views.PostDetailAPI.as_view(), name="get_a_post_detail"),
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  4.5 Test out the blogs API endpoints.
&lt;/h5&gt;

&lt;p&gt;Head over to postman / insomia based on your preferences and test out the blog api's one by one. If you face any issue , feel free to leave a comment or get in touch for more clarifications.&lt;/p&gt;

&lt;h4&gt;
  
  
  5. Implementing the audit logs functionality.
&lt;/h4&gt;

&lt;p&gt;At this stage, you have both authentication and the blog features up and running, you can create, view, edit and delete posts, however, you cannot, as an admin / super user know who accessed what part of the system and the action that was undertaken. This drives us to implement the audit trail functionality.&lt;/p&gt;

&lt;h5&gt;
  
  
  5.1 Create the AuditTrail model.
&lt;/h5&gt;

&lt;p&gt;On your &lt;code&gt;blogs/models.py&lt;/code&gt;, add the audit trail model&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class AuditTrail(TimeStampedUUIDModel):
    login_IP = models.GenericIPAddressField(null=True, blank=True)
    action_datetime = models.DateTimeField(auto_now=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE) # keeps track of the user 
    changed_object = models.CharField(max_length=40)
    event_category = models.CharField(max_length=40)
    user_agent_info = models.CharField(max_length=255)
    is_deleted = models.BooleanField(default=False)
    action = models.CharField(max_length=40)
    change_summary = models.CharField(max_length=199)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run your migrations by using the commands to ensure we can start using the&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;python3 manage.py makemigrations
python3 manage.py migrate

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  5.2 Custom Signal implementation.
&lt;/h5&gt;

&lt;p&gt;With the audit trail model in place, you can now go ahead and create the custom signal implementation that will be used to create the logs.&lt;/p&gt;

&lt;p&gt;Go and create a new file &lt;code&gt;blogs/signals.py&lt;/code&gt; file and add in the following piece of code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
import django.dispatch
from django.dispatch import receiver

from .models import AuditTrail
import logging
import datetime

audit_trail_signal = django.dispatch.Signal(providing_args=['user', 'request', 'model', 'event_category', 'method', 'summary']) # creates a custom signal and specifies the args required. 

logger = logging.getLogger( __name__ )

#helper func that gets the client ip
def get_client_ip(request):
    x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
    if x_forwarded_for:
        ip = x_forwarded_for.split(',')[0]
    else:
        ip = request.META.get('REMOTE_ADDR')
    return ip

@receiver(audit_trail_signal)
def log_audit_trail(sender, user, request, model, event_category, method,summary,**kwargs):
    try:

        user_agent_info = request.META.get('HTTP_USER_AGENT', '&amp;lt;unknown&amp;gt;')[:255],
        print(summary)
        auditTrail = AuditTrail.objects.create( 
            user=user,
            user_agent_info=user_agent_info,
            changed_object = model ,
            event_category = event_category ,
            login_IP = get_client_ip(request),
            is_deleted = False,
            action=method,
            change_summary=summary
        )
        logger.info(f"Audit trail created {auditTrail.id} for user {auditTrail.username} and object {auditTrail.changed_object}")
    except Exception as e:

        logger.error("log_user_logged_in request: %s, error: %s" % (request, e))

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  5.3 Log user actions using the custom signal.
&lt;/h5&gt;

&lt;p&gt;With the setup of the audit trail model and the custom signal done, it is now time to test out whether everything works as expected (finger's crossed). Head over to the &lt;code&gt;views.py&lt;/code&gt; and in the PostAPI view&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class PostAPI(generics.ListCreateAPIView):
    serializer_class = PostSerializer
    queryset = Post.objects.all().order_by("-created_at")
    permission_classes = (permissions.IsAuthenticated,)

    def perform_create(self, serializer):
        data = self.request.data
        new_post = serializer.save(
            user=self.request.user, title=data["title"], content=data["content"]
        )
        all_posts = Post.objects.all().order_by("-created_at")
        serializer = PostSerializer(all_posts, many=True)
        audit_trail_signal.send(sender=request.user. __class__ , request=request, 
        user=request.user, model="Blog",event_category="Blog", method="CREATE")
        return Response(serializer.data, status=status.HTTP_201_CREATED)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  5.4 View to expose logs.
&lt;/h5&gt;

&lt;p&gt;The logs set up is almost done, however as a dev, you may want to access the logs via an API. This is done by first creating a serializer class, the corresponding views and URLs. Go to the &lt;code&gt;blog/serializers.py&lt;/code&gt; and paste in the following piece of code. Do not forget to import the Audit trail model.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class AuditTrailSerializer(serializers.ModelSerializer):
    class Meta:
        model = AuditTrail
        fields = ( 
            "id",
            "action_datetime",
            "user",
            "changed_object",
            "event_category",
            "change_summary",
        )

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The addition of the AuditTrailSerializer sets the stage for the addition of the AuditTrailView and the corresponding URLs&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# don't forget to import the audit trail model and serializer class 

class AuditTrailView(generics.ListAPIView):
    authentication_classes = ( permissions.IsAuthenticated,)
    queryset = AuditTrail.objects.all().order_by('-created')
    serializer_class = AuditTrailSerializer
    permission_classes = ( permissions.IsAuthenticated,)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and add the URL in the &lt;code&gt;blog/urls.py&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#add the following line to your urls.py file 
path('audit-trail/', views.AuditTrailView.as_view(), name="audit_trail"),

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Congratulations, you have built a blog application using Django, Django rest framework and learnt about signals and learnt how to create and use a custom signal.&lt;/p&gt;

&lt;p&gt;Happy hacking.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>k</title>
      <dc:creator>Kipchirchir Langat Emmanuel</dc:creator>
      <pubDate>Fri, 07 Oct 2022 16:56:40 +0000</pubDate>
      <link>https://dev.to/langatmanuk/this-is-a-test-article-dic</link>
      <guid>https://dev.to/langatmanuk/this-is-a-test-article-dic</guid>
      <description></description>
    </item>
    <item>
      <title>Intergrate sonarqube in Jenkins. A gentle intro to Jenkins DevSecOps.</title>
      <dc:creator>Kipchirchir Langat Emmanuel</dc:creator>
      <pubDate>Thu, 06 Oct 2022 21:02:11 +0000</pubDate>
      <link>https://dev.to/langatmanuk/intergrate-sonarqube-in-jenkins-a-gentle-intro-to-jenkins-devsecops-1f7k</link>
      <guid>https://dev.to/langatmanuk/intergrate-sonarqube-in-jenkins-a-gentle-intro-to-jenkins-devsecops-1f7k</guid>
      <description>&lt;p&gt;In this article, you will learn how to set up Jenkins in a digital ocean droplet, configure it, Install sonarqube, configure and link it to our Jenkins pipeline and how to send emails in Jenkins. We will also finally deploy the application to an aws ec2 instance.&lt;/p&gt;

&lt;p&gt;This article assumes a basic understanding of &lt;code&gt;docker&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Set up, configure and install Jenkins on a digital ocean droplet.
&lt;/h4&gt;

&lt;h5&gt;
  
  
  1.1 Head over to &lt;a href="https://www.digitalocean.com/"&gt;Digital Ocean&lt;/a&gt; and create an account if you do not already have one, otherwise log in.
&lt;/h5&gt;

&lt;h5&gt;
  
  
  1.2 Create a digital ocean droplet with the following specs.
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;An image - Ubuntu: the Lts tag&lt;/li&gt;
&lt;li&gt;Plan - 4GB 2 AMD CPUs&lt;/li&gt;
&lt;li&gt;Datacenter region - (preferably one close to your location)&lt;/li&gt;
&lt;li&gt;Authentication method - (ssh keys) and copy your public key to Digital Ocean. follow this link to create ssh keys.&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  1.3 Configure the firewall rules to open port 22 (for ssh connections ) and port 8080 (for our Jenkins server).
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4m8ejjOG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1664096704955/m1N6DN2vP.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4m8ejjOG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1664096704955/m1N6DN2vP.png" alt="Screenshot from 2022-09-25 12-04-55.png" width="880" height="419"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ensure ports 22 and 8080 are open to receive requests.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  1.4 Install docker in the droplet.
&lt;/h5&gt;

&lt;p&gt;On your machine, ssh into the digital ocean droplet by&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh YOUR_DROPLET_IP@root

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the digital ocean droplet by&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apt update

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Upgrade the digital ocean dependencies by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apt upgrade -y

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install docker runtime engine by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apt install docker.io -y

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  1.5 Run Jenkins as a docker container
&lt;/h5&gt;

&lt;p&gt;Run the following command whilst being ssh'ed into the digital ocean droplet.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -p 8080:8080 -p 50000:50000 -d \ 
-v jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $(which docker):/usr/bin/docker jenkins/jenkins:lts

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Access the Jenkins server on the web using the server's public IP as shown below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;YOUR_DO_DROPLET_IP:8080

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After a successful installation of Jenkins in the Docker container, you should see a screen similar to the one below that will prompt you for an administrator password&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#use this command to get the initialAdminPassword
cat /var/lib/docker/volumes/jenkins_home/_data/secrets/initialAdminPassword

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;copy the password and login into Jenkins. We can now create our first Jenkins user.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YSpai1kS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1664097840239/92HrbQsa7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YSpai1kS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1664097840239/92HrbQsa7.png" alt="Screenshot from 2022-09-25 12-23-50.png" width="765" height="518"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Install and configure sonarqube in the digital ocean droplet.
&lt;/h4&gt;

&lt;h5&gt;
  
  
  2.1 SSH into the digital ocean droplet by
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh YOUR_DO_IP@root

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  2.2 Run sonarqube as a docker container
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -d --name sonarqube -p 9000:9000 -p 9092:9092 sonarqube

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;N/B ensure that port 9000 is configured on your firewall and can receive requests&lt;/p&gt;

&lt;p&gt;Login to the sonarqube server by using the default username &lt;code&gt;admin&lt;/code&gt; and default password &lt;code&gt;admin&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You will be redirected to a page where you will reset the default password&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fzBirlEa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1664100379096/0houbSDGn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fzBirlEa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1664100379096/0houbSDGn.png" alt="Screenshot from 2022-09-25 13-04-20.png" width="880" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You will now be redirected to the sonarqube dashboard&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LyHE1yWF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1664100466423/RbaHOhqeQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LyHE1yWF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1664100466423/RbaHOhqeQ.png" alt="Screenshot from 2022-09-25 13-07-05.png" width="880" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You have successfully installed sonarqube and Jenkins on the digital ocean droplet&lt;/p&gt;

&lt;h5&gt;
  
  
  2.3 Configure Sonarqube in Jenkins.
&lt;/h5&gt;

&lt;p&gt;In your Jenkins dashboard, navigate to the manage Jenkins -&amp;gt; Manage Jenkins and install the &lt;a href="https://plugins.jenkins.io/sonar/"&gt;Sonarqube scanner&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vlYVMUns--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1664134372254/nKSVBrIB5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vlYVMUns--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1664134372254/nKSVBrIB5.png" alt="Screenshot from 2022-09-25 22-30-14.png" width="880" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After a successful installation, head over to the manage Jenkins - configure systems and head over to the &lt;strong&gt;Sonarqube Servers&lt;/strong&gt; part and configure it as shown in the pic below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0kvk6i9P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1664137420786/SoP5d-Lgr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0kvk6i9P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1664137420786/SoP5d-Lgr.png" alt="Screenshot from 2022-09-25 23-18-49.png" width="880" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Kindly ensure that you have created a token in Sonarqube by going to the My Account -&amp;gt; Security part and have added the token in Jenkins as a credential.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Create a multi-branch pipeline and configure it for Django.
&lt;/h4&gt;

&lt;p&gt;Head over to your Jenkins Dashboard and click on the &lt;code&gt;New Icon tab&lt;/code&gt;. You will be redirected to this page, input the job name and select the multi-branch job option.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JVV0Fley--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1665082489450/AQhPiUHaN.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JVV0Fley--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1665082489450/AQhPiUHaN.png" alt="Screenshot from 2022-10-06 21-54-38.png" width="880" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On successful creation, head over to the &lt;code&gt;configure section -&amp;gt; branch sources&lt;/code&gt; and set the source as GitHub. Now add in your GitHub credentials previous added and the remote branch.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NrXfpB4---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1665082791328/bJo3E2URC.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NrXfpB4---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1665082791328/bJo3E2URC.png" alt="Screenshot from 2022-10-06 21-59-34.png" width="880" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can now head over to your project and add the following code in the JenkinsFile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#! env/bin/groovy 
def version 
// def newVersion
pipeline {
    agent any 
    stages { 
        stage("Init the application") {
            steps { 
                script {
                    echo "Hello there, ${BRANCH_NAME}"
                }
            }
        }

        stage("Create a virtual enviroment") { 
            steps{
                script{
                    echo "Now creating a virtualenv"
                    sh "python3 -m virtualenv venv"
                    sh "chmod +x venv/"
                    sh "ls"
                    sh ". venv/bin/activate"
                }
            }
        }
        stage("Read the current version of the application") { 
            steps { 
                script { 
                    echo" build number ${BUILD_NUMBER}"
                    def matcher = readFile(" __init__.py") =~ "version = (.+)"
                    echo "${matcher[0][1]}"
                    version = matcher[0][1]
                }
            }
        }
        stage("Test stage") { 
            steps { 
                script{
                    echo "now what"
                    // sh "pytest"
                }
            }
        }
        stage("Build") { 
            steps { 
                script{
                    echo "now what"

                    withCredentials([usernamePassword(credentialsId:'dockerhub-id', usernameVariable:"USER" , passwordVariable:"PASS")]) { 
                        // sh " echo ${PASS} | docker login -u $USER --stdin-"
                        sh ''' 
                    docker system prune -a -f 
                    docker-compose -f docker-compose.yaml down
                    docker-compose -f docker-compose.yaml up --build -d
                    echo $PASS | docker login -u $USER --password-stdin
                    docker push manulangat/django-ecomerce-monolith
                    '''

                    }

                }
            }
        }

        stage('Commit the version and tag'){
            steps {
                script {

                    echo" build number ${BUILD_NUMBER}"
                    def matchers = readFile(" __init__.py") =~ "version = (.+)"
                    echo "${matchers[0][1]}"

                    def vers = matchers[0][1]
                    echo "${vers}"
                    matchers = null
                    // def newVersion = matchers[0][1]
                    // echo "${newVersion}"
                    // sh "docker-compose -f docker-compose.yaml down"
// now
                    withCredentials([usernamePassword(credentialsId:"github-creds-hook", usernameVariable:'USER', passwordVariable:'PASS')]) { 
                        sh '''
                        chmod +x venv/
                        . venv/bin/activate
                        pip install -r requirements.txt

                        git config --global user.name jenkins
                        git config --global user.email jenkins@jobs.com
                        git status
                        git config --list
                        git remote set-url origin https://$USER:$PASS@github.com/manulangat1/ecomerce-monolith.git
                        git push --tags -f
                        git tag | xargs git tag -d
                        chmod +x README.md 
                        chmod +x __init__.py 
                        chmod +x setup.py 
                        chmod +x CHANGELOG.md
                        bump2version minor --allow-dirty
                        git describe --always
                        git push --tags -f
                        git tag | xargs git tag -d

                        '''
                        echo "Done pushing to github"
                    }
                }
            }
        }
    }

}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now connect the sonarqube server to the Jenkins server by going to the Jenkins dashboard and &lt;code&gt;configure systems&lt;/code&gt; and head over to the Sonarqube installations part and fill in the required data.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--utGDZOQK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1665083900341/gzou9RoWn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--utGDZOQK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1665083900341/gzou9RoWn.png" alt="Screenshot from 2022-10-06 22-17-51.png" width="880" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can now add the stage to run sast analysis using sonarqube&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stage('SonarQube Analysis') {
                steps {
                    script {
                        def scannerHome = tool 'SonarScanner';
                            withSonarQubeEnv() {
                            sh "${scannerHome}/bin/sonar-scanner"
                            }
                    }
                }
            }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this stage, your JenkinsFile should resemble the one below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#! env/bin/groovy 
def version 
// def newVersion
pipeline {
    agent any 
    stages { 
        stage("Init the application") {
            steps { 
                script {
                    echo "Hello there, ${BRANCH_NAME}"
                }
            }
        }
        stage('SonarQube Analysis') {
                steps {
                    script {
                        def scannerHome = tool 'SonarScanner';
                            withSonarQubeEnv() {
                            sh "${scannerHome}/bin/sonar-scanner"
                            }
                    }
                }
            }
        stage("Create a virtual enviroment") { 
            steps{
                script{
                    echo "Now creating a virtualenv"
                    sh "python3 -m virtualenv venv"
                    sh "chmod +x venv/"
                    sh "ls"
                    sh ". venv/bin/activate"
                }
            }
        }
        stage("Read the current version of the application") { 
            steps { 
                script { 
                    echo" build number ${BUILD_NUMBER}"
                    def matcher = readFile(" __init__.py") =~ "version = (.+)"
                    echo "${matcher[0][1]}"
                    version = matcher[0][1]
                }
            }
        }
        stage("Test stage") { 
            steps { 
                script{
                    echo "now what"
                    // sh "pytest"
                }
            }
        }
        stage("Build") { 
            steps { 
                script{
                    echo "now what"

                    withCredentials([usernamePassword(credentialsId:'dockerhub-id', usernameVariable:"USER" , passwordVariable:"PASS")]) { 
                        // sh " echo ${PASS} | docker login -u $USER --stdin-"
                        sh ''' 
                    docker system prune -a -f 
                    docker-compose -f docker-compose.yaml down
                    docker-compose -f docker-compose.yaml up --build -d
                    echo $PASS | docker login -u $USER --password-stdin
                    docker push manulangat/django-ecomerce-monolith
                    '''

                    }

                }
            }
        }

        stage('Commit the version and tag'){
            steps {
                script {

                    echo" build number ${BUILD_NUMBER}"
                    def matchers = readFile(" __init__.py") =~ "version = (.+)"
                    echo "${matchers[0][1]}"

                    def vers = matchers[0][1]
                    echo "${vers}"
                    matchers = null
                    // def newVersion = matchers[0][1]
                    // echo "${newVersion}"
                    // sh "docker-compose -f docker-compose.yaml down"
// now
                    withCredentials([usernamePassword(credentialsId:"github-creds-hook", usernameVariable:'USER', passwordVariable:'PASS')]) { 
                        sh '''
                        chmod +x venv/
                        . venv/bin/activate
                        pip install -r requirements.txt

                        git config --global user.name jenkins
                        git config --global user.email jenkins@jobs.com
                        git status
                        git config --list
                        git remote set-url origin https://$USER:$PASS@github.com/manulangat1/ecomerce-monolith.git
                        git push --tags -f
                        git tag | xargs git tag -d
                        chmod +x README.md 
                        chmod +x __init__.py 
                        chmod +x setup.py 
                        chmod +x CHANGELOG.md
                        bump2version minor --allow-dirty
                        git describe --always
                        git push --tags -f
                        git tag | xargs git tag -d

                        '''
                        echo "Done pushing to github"
                    }
                }
            }
        }
    }

}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now push your code to GitHub and head over to your Jenkins Dashboard and navigate to the multi-branch job created earlier and click on the &lt;code&gt;Build now button&lt;/code&gt; to start a new build. Your pipeline should run as expected&lt;/p&gt;

&lt;p&gt;Navigate to your sonarqube server and on the dashboard, you should see your latest build as shown in the image below. You can go through it to understand how your code compares against several metrics.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TmXN_0Kf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1665087491739/VcpNOyRls.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TmXN_0Kf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1665087491739/VcpNOyRls.png" alt="Screenshot from 2022-10-06 23-18-02.png" width="880" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Intergrate Email sending functionality.
&lt;/h4&gt;

&lt;p&gt;Email integrations into the pipeline will help in sending alerts when specific actions occur. This can be achieved by:&lt;/p&gt;

&lt;h5&gt;
  
  
  4.1 Install the email extension library
&lt;/h5&gt;

&lt;p&gt;Head over to your Jenkins dashboard -&amp;gt; manage plugins section and install the &lt;a href="https://plugins.jenkins.io/email-ext/"&gt;Email Extension plugin&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  4.2 Configuring email extension Library
&lt;/h5&gt;

&lt;p&gt;After successful installation, go to the &lt;code&gt;configure system&lt;/code&gt; and scroll down to the extended email part and set up your SMTP servers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oi-aoZtp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1665088817038/KmMNANqnb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oi-aoZtp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1665088817038/KmMNANqnb.png" alt="Screenshot from 2022-10-06 23-40-06.png" width="880" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once that is done, head to your JenkinsFile and add the following block after all the stages.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    post{ 
    always { 
        sh '''
        docker system prune -a -f 
        docker-compose -f docker-compose.yaml down
        rm -rf venv
        '''
        emailext body: "$JOB_NAME - Build # $BUILD_NUMBER - :Check console output at $BUILD_URL to view the results.", recipientProviders: [[$class: 'DevelopersRecipientProvider'], [$class: 'RequesterRecipientProvider']], subject: 'Test'
    }
    failure { 
        echo "oops sth failed"
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This step shuts down our docker containers and sends an email about the build. Commit and push your code to GitHub and head over to Jenkins to trigger a build. You should receive an email about the build details.&lt;/p&gt;

&lt;p&gt;In this article, we have gone through setting up Jenkins, Sonarqube and email integration and how they work together in a pipeline. In the next article, we shall look at how to set up slack notifications in the pipeline and how to integrate dast (dynamic application software testing) in the pipeline.&lt;/p&gt;

&lt;p&gt;Happy hacking&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Deploy a Django image to Jenkins using a multi-branch pipeline and conditionals.</title>
      <dc:creator>Kipchirchir Langat Emmanuel</dc:creator>
      <pubDate>Thu, 08 Sep 2022 17:35:54 +0000</pubDate>
      <link>https://dev.to/langatmanuk/deploy-a-django-image-to-jenkins-using-a-multi-branch-pipeline-and-conditionals-2lj6</link>
      <guid>https://dev.to/langatmanuk/deploy-a-django-image-to-jenkins-using-a-multi-branch-pipeline-and-conditionals-2lj6</guid>
      <description>&lt;p&gt;This is the fifth article in the series &lt;a href="https://blog.kipchirchirlangat.com/series/jenkins-guide-django"&gt;Deploy a Django app to AWS EC2 instance using Jenkins. A gentle guide to Jenkins.&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this article, you will build and configure a multi-branch Jenkins pipeline that will deploy a Django image to Dockerhub. You are required to have gone through the other articles in the series beforehand.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Now, you might wonder, what exactly is a multi-branch pipeline?&lt;/strong&gt; The Multibranch Pipeline project type enables you to implement different Jenkinsfiles for different branches of the same project. In a Multibranch Pipeline project, Jenkins automatically discovers, manages and executes Pipelines for branches which contain a Jenkinsfile in source control.&lt;/p&gt;

&lt;p&gt;This eliminates the need for manual Pipeline creation and management.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Create a multi-branch pipeline on Jenkins.
&lt;/h4&gt;

&lt;p&gt;Head over to your Jenkins dashboard and click on the &lt;code&gt;new item&lt;/code&gt; tab. Continue with the creation by giving the job a name and selecting the &lt;code&gt;multi-branch pipeline&lt;/code&gt; option.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DwAsgJ4D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1662193708419/fCcZDFKAS.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DwAsgJ4D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1662193708419/fCcZDFKAS.png" alt="Screenshot from 2022-09-03 11-28-18.png" width="880" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upon successful creation, click on the &lt;code&gt;branch sources&lt;/code&gt; tab and on the drop-down, select either Git or GitHub depending on the version control in use.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SeebSvho--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1662194008183/ZT_lBmEOU.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SeebSvho--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1662194008183/ZT_lBmEOU.png" alt="Screenshot from 2022-09-03 11-33-13.png" width="880" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now onto configuring the sources after selection. Attach the GitHub credentials you had earlier configured, and add your repo name in the &lt;code&gt;project URL&lt;/code&gt; input box. On the &lt;code&gt;discover branches&lt;/code&gt; dropdown, select the &lt;code&gt;Filter by name (with regular expression)&lt;/code&gt; option. In the input, add the following regex&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.* // dynamically discovers and loads all the branches (master, feature, hot fix etc)

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Click on save and it should scan your GitHub repo branches if any Jenkins file exists and build the job.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YRJHwsEO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1662194734283/EJuKq_vz1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YRJHwsEO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1662194734283/EJuKq_vz1.png" alt="Screenshot from 2022-09-03 11-44-14.png" width="880" height="467"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You have now successfully created and configured your multi-branch pipeline.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Use conditionals in Jenkins.
&lt;/h4&gt;

&lt;p&gt;Let's mimic a production workflow and you want to push the Django image to Dockerhub for the staging environment only. The below steps will guide you on how to do it.&lt;/p&gt;

&lt;p&gt;Create and switch into a &lt;code&gt;staging&lt;/code&gt; branch by using the commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; git switch -c "feat-staging"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Confirm that you are in the staging branch by&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git branch

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All good now, now shift the focus to the JenkinsFile, suppose you want to only push our docker image to Dockerhub when in the staging branch, how can that be achieved? Enter the use of the &lt;code&gt;when&lt;/code&gt; block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stage('build') { 
            when { 
                expression { 
                    BRANCH_NAME == 'staging' //this expression make sure that this step is only run when the branch name is staging
                }

            }
            steps{
                script { 
                    gv.buildApp()
                }
            }
        }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have now successfully created, and configured a multi-branch pipeline in Jenkins and learnt how to use conditionals in Jenkins. In the next article, you will learn how to install, configure and use sonarqube in Jenkins.&lt;/p&gt;

&lt;p&gt;Happy hacking!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Jenkins pipeline to build and push a Django image to dockerhub and GitHub webhook integration.</title>
      <dc:creator>Kipchirchir Langat Emmanuel</dc:creator>
      <pubDate>Wed, 31 Aug 2022 11:41:25 +0000</pubDate>
      <link>https://dev.to/langatmanuk/jenkins-pipeline-to-build-and-push-a-django-image-to-dockerhub-and-github-webhook-integration-47pd</link>
      <guid>https://dev.to/langatmanuk/jenkins-pipeline-to-build-and-push-a-django-image-to-dockerhub-and-github-webhook-integration-47pd</guid>
      <description>&lt;p&gt;This is the fourth article in the series &lt;a href="https://blog.kipchirchirlangat.com/series/jenkins-guide-django"&gt;Deploy a Django app to AWS EC2 instance using Jenkins. A gentle guide to Jenkins.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this article, you will piece together all the fundamentals that you have learned and build a full Jenkins pipeline that will build and deploy a Django image to Dockerhub. You are required to have gone through the previous articles beforehand&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Add the init stage and load the &lt;code&gt;script.groovy&lt;/code&gt; file.
&lt;/h4&gt;

&lt;p&gt;In your JenkinsFile, add the init stage that loads our groovy script.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def gv // we define this here to make it globally available. 
pipeline { 

    agent any
    stages { 

        stage('Init') { 

            steps { 
                script { 
                    gv = load "script.groovy"
                }
            }
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that you should have a &lt;code&gt;script.groovy&lt;/code&gt; file at the root of your project. If not , kindly create it by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch script.groovy

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following code inside the &lt;code&gt;script.groovy&lt;/code&gt; file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def buildApp() { 
    echo "Building app"
}
return this // returns all the funcs inside the file.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Add a test stage to your JenkinsFile (optional).
&lt;/h4&gt;

&lt;p&gt;You will now add a test stage to your JenkinsFile. This is however optional and you may add it if you want to run some tests.&lt;/p&gt;

&lt;p&gt;You will first add a &lt;code&gt;testApp&lt;/code&gt; function in your &lt;code&gt;script.groovy&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def testApp() { 
    echo "Testing our application" 
    // you can now run your test command here, e.g if using pytest you run 
    sh "pytest"
}

def buildApp() { 
    echo "Building app"
}

return this

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now use the &lt;code&gt;testApp&lt;/code&gt; func in the test stage in your JenkinsFile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stage ('test') { 
            steps { 
                script {
                    gv.testApp()
                }
            }
        }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;Disclaimer: This step is optional and can be skipped unless you have tests that you want to run.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Add a build stage to your pipeline.
&lt;/h4&gt;

&lt;p&gt;You can now add a build stage to your JenkinsFile, as usual, you first start with adding the &lt;code&gt;buildApp&lt;/code&gt; function in the &lt;code&gt;script.groovy&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;You will make use of the &lt;code&gt;withPassword&lt;/code&gt; functionality that you had covered before and the dockerhub credentials we had earlier created.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def buildApp() { 
    echo "Building app with build number #${env.BUILD_NUMBER}" // env variables are available and can be accesed in groovy files.
    withPassword([credentialsId:'dockerhub-id', passwordVariable: 'PASS', usernameVariable:'USER']){
        sh "docker build . -t YOUR_REPO_NAME:YOUR_TAG" // replace YOU_REPO_NAME and YOUR_TAG with the respective repo name and tag.
        sh "echo $PASS | docker login -u $USER --password-stdin"
        sh " docker push YOUR_REPO_NAME:YOUR_TAG" // replace YOU_REPO_NAME and YOUR_TAG with the respective repo name and tag.
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now use this in the build step&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stage('build') { 
            steps{
                script { 
                    gv.buildApp()
                }
            }
        }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  4. Add a deploy step to Jenkins pipeline.
&lt;/h4&gt;

&lt;p&gt;You first add a &lt;code&gt;deployApp&lt;/code&gt; to the script.groovy file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def deployApp() { 
    echo "We will handle this in the next article!"
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And use it in our JenkinsFile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
stage("deploy"){ 
            steps{
                gv.deployApp()
            }
        }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the moment, your &lt;code&gt;script.groovy&lt;/code&gt; should be similar to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// script.groovy
def testApp() { 
    echo "Testing our application" 
    // you can now run your test command here, e.g if using pytest you run 
    sh "pytest"
}

def buildApp() { 
    echo "Building app with build number #${env.BUILD_NUMBER}" // env variables are available and can be accesed in groovy files.
    withPassword([credentialsId:'dockerhub-id', passwordVariable: 'PASS', usernameVariable:'USER']){
        sh "docker build . -t YOUR_REPO_NAME:YOUR_TAG" // replace YOU_REPO_NAME and YOUR_TAG with the respective repo name and tag.
        sh "echo $PASS | docker login -u $USER --password-stdin"
        sh " docker push YOUR_REPO_NAME:YOUR_TAG" // replace YOU_REPO_NAME and YOUR_TAG with the respective repo name and tag.
    }
}
def deployApp() { 
    echo "We will handle this in the next article!"
}
return this

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And the JenkinsFile&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def gv // define here for it to be globally available
pipeline { 

    agent any
    parameters { 
        choice(name: 'Version', choices:['1.1.0', '1.2.0', '1.3.0'], description:'')
    }
    stages { 

        stage('Init') { 

            steps { 
                script { 
                    gv = load "script.groovy"
                }
            }
        }
        stage ('test') { 
            steps { 
                script {
                    gv.testApp()
                }
            }
        }
        stage('build') { 
            steps{
                script { 
                    gv.buildApp()
                }
            }
        }

        stage("deploy"){ 
            steps{
                gv.deployApp()
            }
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now commit and push your changes to the version control of your choice then head over to your Jenkins dashboard and build. It should build successfully without any error. If you need any clarifications, kindly leave a comment and I will reply as fast as I can.&lt;/p&gt;

&lt;h4&gt;
  
  
  5. Integrate with GitHub.
&lt;/h4&gt;

&lt;p&gt;Up to this point, you have been manually building our jobs, however, in large development teams, this is highly inefficient. You will now look at how to integrate GitHub with our jenkins server so that the jobs can run automatically.&lt;/p&gt;

&lt;p&gt;Head over to your GitHub dashboard and click on the settings tab and navigate to the webhooks section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NaJKz0xo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661939779533/_qb-EnWeW.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NaJKz0xo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661939779533/_qb-EnWeW.png" alt="Screenshot from 2022-08-31 12-56-05.png" width="880" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the Payload URL field, paste your Jenkins environment URL. At the end of this URL add /github-webhook/. In the Content type select: application/json and leave the Secret field empty&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--viSQpyJo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661939953119/K86ff6947.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--viSQpyJo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661939953119/K86ff6947.png" alt="Screenshot from 2022-08-31 12-59-01.png" width="880" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the page Which events would you like to trigger this webhook? choose Let me select individual events. Then, check Pull Requests and Pushes. At the end of this option, make sure that the Active option is checked and click on Add webhook.&lt;/p&gt;

&lt;p&gt;You are done with configurations on GitHub, now move to your Jenkins dashboard, select the job that you had created initially and select the &lt;code&gt;Build triggers&lt;/code&gt; tab after clicking on &lt;code&gt;configure&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--DxlpEU9E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661940310061/9c6VP3LbR.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DxlpEU9E--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661940310061/9c6VP3LbR.png" alt="Screenshot from 2022-08-31 13-05-02.png" width="880" height="474"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check on the &lt;code&gt;GitHub hook trigger for GITScm polling&lt;/code&gt; option.&lt;/p&gt;

&lt;p&gt;You have now successfully integrated GitHub with Jenkins. Head over to your code editor, make a change, push it to GitHub and you should see a build automatically runs.&lt;/p&gt;

&lt;p&gt;In this article, you have come up with a full Jenkins pipeline that pushes a Django image to dockerhub and you have integrated GitHub with Jenkins for automated builds. In the next article, you will learn how to use &lt;code&gt;Multi-branch pipelines&lt;/code&gt; , &lt;code&gt;conditionals&lt;/code&gt; and how to set up email notifications (finally)&lt;/p&gt;

&lt;p&gt;Happy hacking.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>An introduction to Jenkins environment variables, parameters and use of groovy scripts.</title>
      <dc:creator>Kipchirchir Langat Emmanuel</dc:creator>
      <pubDate>Tue, 30 Aug 2022 16:19:57 +0000</pubDate>
      <link>https://dev.to/langatmanuk/an-introduction-to-jenkins-environment-variables-parameters-and-use-of-groovy-scripts-3534</link>
      <guid>https://dev.to/langatmanuk/an-introduction-to-jenkins-environment-variables-parameters-and-use-of-groovy-scripts-3534</guid>
      <description>&lt;p&gt;This is the third article in the series &lt;a href="https://blog.kipchirchirlangat.com/series/jenkins-guide-django"&gt;Deploy a Django app to AWS EC2 instance using Jenkins. A gentle guide to Jenkins&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In this article, we will go through how to use variables and parameters in Jenkins and how to use groovy scripts. We will be using the same project as before. You are required to have gone through the previous articles beforehand.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. How to configure and use variables in a JenkinsFile.
&lt;/h4&gt;

&lt;p&gt;While writing a JenkinsFile pipeline script, you may need to inject and use some dynamic values thus avoiding the hassle of hardcoding values in the pipeline hence the need for environment variables.&lt;/p&gt;

&lt;p&gt;Jenkins environment variable is a global variable, exposed via env variable and used in Jenkins pipelines and anywhere in your Jenkinsfile file /Pipeline. Any value stored as the environment variable in the env variable is of string type.&lt;/p&gt;

&lt;p&gt;Jenkins already has a list of pre-defined environment variables that you can use in your pipeline. A comprehensive list of the variables can be found by accessing the below URL on your browser.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;${JENKINS_IP}/env-vars.html/
// Substitute JENKINS_IP with the IP address of the digital ocean droplet hosting our Jenkins server.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should expect to see a page with all the Jenkins env variables.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--T7E5xhrQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661869671818/oyt8Yy4FW.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--T7E5xhrQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661869671818/oyt8Yy4FW.png" alt="Screenshot from 2022-08-30 17-24-57.png" width="880" height="427"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now that you can access a list of the environment variables, let us now access them in our JenkinsFile.&lt;/p&gt;

&lt;p&gt;To access the environment variables in our JenkinsFile, we use the &lt;code&gt;env&lt;/code&gt; object. The reference to Jenkins pipeline environment variables is made by surrounding it by&lt;code&gt;${}&lt;/code&gt; in the following way: &lt;code&gt;${env.ENV_VARIABLE}&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Let us now add an init stage in the JenkisFile where we can see this in use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stage('Init') { 
            steps { 
                echo "Hello, this is build number ${env.BUILD_NUMBER}"
            }
        }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also access the environment variables without the env object&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stage('Init') { 
            steps { 
                echo "Hello, this is build number ${BUILD_NUMBER}"
            }
        }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, for pre-defined variables, it is common practice to access them with the env object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Local environment variables in Jenkins&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can also define your own environment variables in a JenkinsFile Script. This is done by adding your variable to an environment block.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipeline {
   agent any
   environment {
       DISABLE_AUTH = 'true' //can be used in whole pipeline
   }
   stages {
       stage(Build) {
           steps {
               echo env.DISABLE_AUTH
           }
       }
   }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also define local environment variables for a specific stage&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipeline {
   agent any
   environment {
       DISABLE_AUTH = 'true'
   }
   stages {
       stage(Build) {
           environment {
                   ENABLE_AUTH = false //can be used in this stage only
              }
           steps {
               echo env.DISABLE_AUTH
               echo env.ENABLE_AUTH
           }
       }
   }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;You can also access credentials created via the GUI in the environment block. However, that is out of the scope of this article.&lt;/em&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Parameters in your Jenkins.
&lt;/h4&gt;

&lt;p&gt;You can also provide parameters in your Jenkins script. The parameters can be of the following types.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;String parameters. &lt;/li&gt;
&lt;li&gt;Boolean parameters. &lt;/li&gt;
&lt;li&gt;Multi-line string parameters. &lt;/li&gt;
&lt;li&gt;Choice parameters.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;For the purpose of this article, we are going to see a use case which involves the use of choice parameters.&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipeline { 

    agent any
    parameters { 
        choice(name: 'Version', choices:['1.1.0', '1.2.0', '1.3.0'], description:'')
    }
    stages { 

        stage('Init') { 

            steps { 

                echo "Hello, this is build number ${BUILD_NUMBER}"
            }
        }
        stage("deploy"){ 
            steps{
                echo "Deploying Version ${VERSION}"
            }
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now head over to the Jenkins dashboard and you will see a &lt;code&gt;build with parameters&lt;/code&gt; option and which upon selecting the version a build will commence.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--q2nfBQ94--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661873463777/TeY1NI3Mz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--q2nfBQ94--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661873463777/TeY1NI3Mz.png" alt="Screenshot from 2022-08-30 18-29-38.png" width="880" height="236"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclaimer: This is simple into to parameters in Jenkins, a more in-depth article on the same is in the works.&lt;/em&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Refactor the build step into a groovy script. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You will now start decomposing and refactoring the build step in our JenkisFile by moving the docker build commands into a groovy script. You can read more about the groovy scripts and its use-case in Jenkins in the &lt;a href="https://www.jenkins.io/doc/pipeline/steps/workflow-cps/"&gt;documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a file named &lt;code&gt;script.groovy&lt;/code&gt; at the root of the project and add the following code to it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def buildApp() { 
    echo "Building app"
}
return this

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use this script in your JenkinsFile, add a script block in the init stage and load the file as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        stage('Init') { 

            steps { 
                script { 
                    gv = load "script.groovy"
                }
            }
        }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To make this globally available we can define it at the top of our file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;def gv 
pipeline { 

    agent any
    parameters { 
        choice(name: 'Version', choices:['1.1.0', '1.2.0', '1.3.0'], description:'')
    }
    stages { 

        stage('Init') { 

            steps { 
                script { 
                    gv = load "script.groovy"
                }
            }
        }
        stage("deploy"){ 
            steps{
                echo "Deploying Version ${VERSION}"
            }
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You are now able to access the &lt;code&gt;buildApp&lt;/code&gt; function defined in the &lt;code&gt;script.groovy&lt;/code&gt; file by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;stage('build') { 
            steps{
                scripts { 
                    gv.buildApp()
                }
            }
        }

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Commit your code to version control and run a new build and it should pass.&lt;/p&gt;

&lt;p&gt;We have introduced a new concept, the use of groovy scripts and this will be fully discussed in the next article.&lt;/p&gt;

&lt;p&gt;At this stage, you should be fairly comfortable with using environment variables and parameters in Jenkins and should have a basic knowledge of the use case of groovy scripts and its importance. In the next article, we will now write a Jenkins file that builds, run tests and pushes our docker image to dockerhub by building on the foundations we have gone through today ( env variables, parameters, user inputs and use of groovy scripts.). We shall also set up email notifications to notify us of the build status (success/failure).&lt;/p&gt;

&lt;p&gt;Happy hacking.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Dockerizing a Nest js application and deploying to Dockerhub (without docker-compose)</title>
      <dc:creator>Kipchirchir Langat Emmanuel</dc:creator>
      <pubDate>Sun, 28 Aug 2022 14:58:53 +0000</pubDate>
      <link>https://dev.to/langatmanuk/dockerizing-a-nest-js-application-and-deploying-to-dockerhub-without-docker-compose-31g</link>
      <guid>https://dev.to/langatmanuk/dockerizing-a-nest-js-application-and-deploying-to-dockerhub-without-docker-compose-31g</guid>
      <description>&lt;p&gt;Hi Peeps, Today we will look at how to dockerize a node application and deploy it to docker hub. We will be using &lt;a href="https://github.com/manulangat1/nest-docker-jenkins.git"&gt;this&lt;/a&gt; project for demo purposes.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Clone application
&lt;/h4&gt;

&lt;p&gt;Navigate to your preferred folder and clone the application&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd Desktop 
git clone https://github.com/manulangat1/nest-docker-jenkins.git

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Create your docker file.
&lt;/h4&gt;

&lt;p&gt;Once you have cloned your project, on the root of the project create a file Dockerfile.&lt;br&gt;&lt;br&gt;
A Dockerfile is a text document that contains all the commands that a user would call on the command line for an image to be built.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:13-alphine # this is the base image in which our image will be based on. 
WORKDIR /usr/src/app # this sets the working directory for our image 
COPY package*.json . # this command copies the package.json and package-lock.json 
files from our host container to the docker container. 
EXPOSE 3000 # this exposes our port on the docker .
RUN npm install # this installs all our dependencies 
COPY . . # this copies all the other files from our host to our docker container
CMD ["npm" , "start:dev"] # this is the entry point of our application

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  3. Build our docker image.
&lt;/h4&gt;

&lt;p&gt;We are now going to build our image using docker&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t nest-docker:nd-1.0 .

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-t commands&lt;/code&gt; tells docker to tag our image with the name &lt;code&gt;nest-docker&lt;/code&gt; and the &lt;code&gt;.&lt;/code&gt; context tells it to look for the Dockerfile at the root of the project.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Run the docker image
&lt;/h4&gt;

&lt;p&gt;We will now run our docker image&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run -p 3000:3000 --name nest-service nest-docker:nd-1.0

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-p&lt;/code&gt; binds our port to the port we had earlier exposed and &lt;code&gt;--name&lt;/code&gt; gives a name to the current container that we are running.&lt;/p&gt;

&lt;h4&gt;
  
  
  5. Deploying to docker hub.
&lt;/h4&gt;

&lt;p&gt;Head over to &lt;a href="https://hub.docker.com/"&gt;Dockerhub&lt;/a&gt; and create an account if you do not have one. Once you log in, create a repository and we are set to deploy our docker image to docker hub.&lt;/p&gt;

&lt;p&gt;Run the following command to log in to dockerhub.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker login

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To push our docker image to docker hub, run the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker push nest-docker:nd-1.0

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You have now built and deployed a dockerized nest application to dockerhub.&lt;/p&gt;

&lt;p&gt;Follow me for more articles on docker, Jenkins and DevOps in general.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Set up Jenkins pipeline jobs to deploy a Django image to dockerhub</title>
      <dc:creator>Kipchirchir Langat Emmanuel</dc:creator>
      <pubDate>Fri, 26 Aug 2022 14:50:27 +0000</pubDate>
      <link>https://dev.to/langatmanuk/set-up-jenkins-pipeline-jobs-to-deploy-a-django-image-to-dockerhub-454e</link>
      <guid>https://dev.to/langatmanuk/set-up-jenkins-pipeline-jobs-to-deploy-a-django-image-to-dockerhub-454e</guid>
      <description>&lt;p&gt;This is the second tutorial in the &lt;a href="https://blog.kipchirchirlangat.com/series/jenkins-guide-django"&gt;Deploy a Django app to AWS EC2 instance using a Jenkins server&lt;/a&gt; series.&lt;/p&gt;

&lt;p&gt;In this article, we will go through how to give our Jenkins permission to run docker commands and set up a basic pipeline job that deploys our Django docker build to dockerhub.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Give access to the jenkins user to run docker commands.
&lt;/h4&gt;

&lt;p&gt;ssh into our droplet by using the commands&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ssh root@YOUR-IP

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Get the jenkins container id using the commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; docker ps

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see an output similar to the one below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QhSW-7s2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661519003215/x_oURH5ah.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QhSW-7s2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661519003215/x_oURH5ah.png" alt="Screenshot from 2022-08-26 16-02-57.png" width="880" height="41"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once we have the container id, we can now get into the container by using the commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker exec -it CONTAINER_ID bash

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;run &lt;code&gt;docker&lt;/code&gt; and you should be able to see a list of all docker commands.&lt;/p&gt;

&lt;p&gt;Let's now try to run a Redis image by the commands&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run redis

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait, what happened? We should be hit with the following error&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1XfebNmj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661519547447/xxSyzejiu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1XfebNmj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661519547447/xxSyzejiu.png" alt="Screenshot from 2022-08-26 16-11-05.png" width="880" height="51"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This error means that jenkins user does not have sufficient permissions to run certain commands.&lt;/p&gt;

&lt;p&gt;Exit the session and get into the container as a root user by first running &lt;code&gt;docker ps&lt;/code&gt; to get the container id, we will now get into the container as a root user by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker exec -u 0 -it CONTAINER_ID bash

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now give our Jenkins user the permissions by:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod 666 /var/run/docker.sock

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To verify that all went well, run &lt;code&gt;ls -l var/run/docker.sock&lt;/code&gt; and you should expect an output like the one in the picture below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nn90RG4Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661520201517/v3oe3iUDN.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nn90RG4Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661520201517/v3oe3iUDN.png" alt="Screenshot from 2022-08-26 16-23-13.png" width="880" height="34"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To verify that all is well, get into the jenkins container as the jenkins user and run &lt;code&gt;docker run redis&lt;/code&gt;. The error that we previously encountered should be non-existent and the command should run successfully.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Create a pipeline to deploy a Django docker image to dockerhub.
&lt;/h4&gt;

&lt;p&gt;Head over to your jenkins page and create a new pipeline job&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9IHqD-Jc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661521401946/cri5uptNM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9IHqD-Jc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661521401946/cri5uptNM.png" alt="Screenshot from 2022-08-26 16-43-12.png" width="880" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After successful creation, we need to connect it to our repository by clicking on the pipeline tab and scrolling down to the pipeline section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pkjYHdvo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661521556921/rbzZSNrBe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pkjYHdvo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661521556921/rbzZSNrBe.png" alt="Screenshot from 2022-08-26 16-45-30.png" width="880" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the pipeline script from SCM option on the dropdown and add in the repo URL.&lt;br&gt;&lt;br&gt;
 Make sure to add your github/ gitlab credentials as a username with a password option and the branch in which your JenkinsFile exists.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dVLm3sXe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661522091675/o_e3_ZoEo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dVLm3sXe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661522091675/o_e3_ZoEo.png" alt="Screenshot from 2022-08-26 16-54-05.png" width="880" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In your Django project, make sure that the JenkinsFile exists, we can now proceed to add the Jenkins configurations.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipeline { 
    agent any 
    stages { 
        stage('Build') { 
            steps { 
                sh 'echo "Hello World"'
            }
        }
        stage('Done'){
            steps {
                echo " Wow! I'm done!"
            }
        }
        stage('Deploy staging ') { 
            steps { 
                echo 'I am deploying to a staging server
            }
        }

        stage ( 'Deploy prod') { 
            steps { 
                echo 'I am deploying to prod server

            }
        }
    }}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can now push your code to your version control and head over to your Jenkins server web page, get into the job we created and click on the build now button to start a build.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rmOlQloh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661522869561/orTPQBuD8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rmOlQloh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661522869561/orTPQBuD8.png" alt="Screenshot from 2022-08-26 17-06-31.png" width="880" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You should be able to see your build status with the build number, you can click on the build number and it will redirect you to the build.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vierwtqJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661523095136/356gcor-F.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vierwtqJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661523095136/356gcor-F.png" alt="Screenshot from 2022-08-26 17-10-42.png" width="880" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cVc3VMjw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661523134406/KqmZETSOk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cVc3VMjw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661523134406/KqmZETSOk.png" alt="Screenshot from 2022-08-26 17-12-05.png" width="880" height="455"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To check on the console output info, you can click on the console output.&lt;/p&gt;

&lt;p&gt;We can go ahead and configure a stage that will build and deploy our Django image to dockerhub. Make sure that you have installed the credentials and the credentials binding plugins for this next step. Add your docker hub credentials with an id for you to be able to access it in your JenkinsFile.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pipeline { 
    agent any 
    stages { 
        stage('Build docker image') { 
            steps { 
                sh 'echo "Hello World"'
                script{ 
                //    
                withCredentials([ 
                    usernamePassword(credentials:'docker-hub-credentials', usernameVariable:USER, passwordVariable:PASSWORD)
                ]) { 
                    sh "docker build . -t YOUR_IMAGE_NAME"
                    sh "echo $PASSORD | docker login -u $USER --password-stdin"
                    sh "docker push YOUR_IMAGE_NAME"
                }
                }
            }
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have introduced a new concept, the &lt;code&gt;withCredentials&lt;/code&gt; tool that we will discuss comprehensively in the next article.&lt;/p&gt;

&lt;p&gt;At this stage, you have now set up Jenkins on a digital ocean droplet and used it to deploy a Django image to Dockerhub. In the next article, we shall cover how to use groovy scripts, and environment variables and set up a GitHub trigger that will run our builds automatically.&lt;/p&gt;

&lt;p&gt;Cheers.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Set up Jenkins server on a digital ocean droplet.</title>
      <dc:creator>Kipchirchir Langat Emmanuel</dc:creator>
      <pubDate>Thu, 25 Aug 2022 12:33:03 +0000</pubDate>
      <link>https://dev.to/langatmanuk/set-up-jenkins-server-on-a-digital-ocean-droplet-3h2e</link>
      <guid>https://dev.to/langatmanuk/set-up-jenkins-server-on-a-digital-ocean-droplet-3h2e</guid>
      <description>&lt;p&gt;This article will go through the steps needed to set up a Jenkins instance on a digital ocean droplet&lt;/p&gt;

&lt;p&gt;What is Jenkins?&lt;/p&gt;

&lt;p&gt;Jenkins is an open-source automation server that helps development teams to automate repetitive tasks in CI/CD&lt;/p&gt;

&lt;p&gt;Let's now head to set up our Jenkins server.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Register for a digital ocean account &lt;a href="https://cloud.digitalocean.com/registrations/new"&gt;here&lt;/a&gt;
&lt;/h3&gt;

&lt;h3&gt;
  
  
  2. Create a droplet with the following specs.
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;An image - Ubuntu: the Lts tag&lt;/li&gt;
&lt;li&gt;Plan - 4GB 2 AMD CPUs&lt;/li&gt;
&lt;li&gt;Datacenter region - (preferably one close to your location)&lt;/li&gt;
&lt;li&gt;Authentication method - (ssh keys) and copy your public key to Digital Ocean. follow this link to create ssh keys.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3. Configure firewall rules to open ports 22 and 8080 that our Jenkin server will use.
&lt;/h3&gt;

&lt;p&gt;Click on the newly created droplet and navigate to the networking tab.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5y3MH5cM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661426646409/P3u2vJplq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5y3MH5cM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661426646409/P3u2vJplq.png" alt="Screenshot from 2022-08-25 14-23-51.png" width="880" height="550"&gt;&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Ensure that ports 22 and 8080 are open to receive requests.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9UPmaOao--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661426794377/0CS249Q8V.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9UPmaOao--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1661426794377/0CS249Q8V.png" alt="Screenshot from 2022-08-25 14-25-59.png" width="880" height="550"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Install docker and run Jenkin as a docker container.
&lt;/h3&gt;

&lt;h4&gt;
  
  
  4.1 ssh into the droplet by using the command
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;         ```


            ssh root@YOUR_IP


#### 4.2. Update the server by using the command.



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;apt update&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


#### 4.3. Install recommended upgrades.



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;apt upgrade -y&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


#### 4.4. Install docker runtime engine.



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;apt install docker.io -y&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


## 5. Run Jenkins as a docker container using the following command



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;docker run -p 8080:8080 -p 50000:50000 -d \ &lt;br&gt;
-v jenkins_home:/var/jenkins_home \&lt;br&gt;
-v /var/run/docker.sock:/var/run/docker.sock \&lt;br&gt;
-v $(which docker):/usr/bin/docker jenkins/jenkins:lts&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


### 6. Access the Jenkins server on the web using the server's public IP as shown below



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;134.xxx.xx.xxx:8080&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


After a successful installation of Jenkins in the Docker container, you should see a screen similar to the one below that will prompt you for an administrator password



&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h1&gt;
  
  
  use this command to get the initialAdminPassword
&lt;/h1&gt;

&lt;p&gt;cat /var/lib/docker/volumes/jenkins_home/_data/secrets/initialAdminPassword&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;


copy the password and login into Jenkins. We can now create our first Jenkins user.

![Screenshot from 2022-08-25 15-07-43.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1661429412236/lz0Kc6M0H.png)

We have now successfully installed Jenkins.

In our next article, we shall go through how to deploy a Django application to an ec2 instance using the Jenkins server we have set up.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
    </item>
    <item>
      <title>Dockerizing a nest app and deploying to Dockerhub (with Docker compose)</title>
      <dc:creator>Kipchirchir Langat Emmanuel</dc:creator>
      <pubDate>Sun, 03 Jul 2022 20:42:08 +0000</pubDate>
      <link>https://dev.to/langatmanuk/dockerizing-a-nest-app-and-deploying-to-dockerhub-with-docker-compose-44dg</link>
      <guid>https://dev.to/langatmanuk/dockerizing-a-nest-app-and-deploying-to-dockerhub-with-docker-compose-44dg</guid>
      <description>&lt;p&gt;Hello peeps,&lt;/p&gt;

&lt;p&gt;In this article, we will go through how to deploy a nest app to dockerhub. The prerequisites needed are a dockerhub account and having docker and docker compose locally installed. We will be using this &lt;a href="https://github.com/manulangat1/nest-bookmark-api"&gt;project&lt;/a&gt; as our starting point&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Clone the application.
&lt;/h4&gt;

&lt;p&gt;Navigate into your desired folder and clone the app using the following commands&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd Desktop 
git clone https://github.com/manulangat1/nest-bookmark-api

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once done, navigate into the cloned project&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Adding a docker file.
&lt;/h3&gt;

&lt;p&gt;A docker file is a text document that contains all the commands that will be used to build a docker image. At the root of your project, create a new file Dockerfile&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch Dockerfile

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now start adding our commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM node:13-alphine # this is the base image that our docker image will be based on
WORKDIR /usr/src/app # this sets the working directory on our docker container 
COPY package*.json . #this command copies the package.json and package-lock.json from our host to the docker container 
RUN npm install # this installs all the packages defined in our package.json file. 
EXPOSE 3000 # exposes the port on our container 
COPY . . #copies everything from our host to our docker container
CMD ["npm" , "start:dev"] # this is the entry point of our application

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  3. Setting up our docker-compose file.
&lt;/h3&gt;

&lt;p&gt;At the root of the project, create a new file called &lt;code&gt;docker-compose.yml&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;touch docker-compose.yml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can now proceed to add our docker-compose commands. Note that we will not spin up and database for this part, a more detailed post on docker-compose is in the works.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;services:'3' # this tells the version of docker-compose that we are using. 
  dev-api: #this is the name of our container 
      build: . This tells docker-compose to look for the Dockerfile at the root (path where Dockerfile lives)
      environment:
      ports: # this binds the port on our local machine to our docker container
          - "3000:3000"  
      volumes: # creating a volume enables us to have a way of persisting our data. More about this soon. (we are using a named volume here)
          - db-data:/var/lib/postgresql/data
      restart: always # tells the behaviour of our application once the docker container fails

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Fire up our docker container.
&lt;/h3&gt;

&lt;p&gt;Moment of truth, we are going to fire up our container using the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; docker-compose up dev-api -d

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;-d&lt;/code&gt; tells the container to run in a detached mode.&lt;/p&gt;

&lt;p&gt;To confirm whether our container is running, use the command below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker ps

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and your output should be in the form of : &lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--juFNlruK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1656880352238/-ZBKdpkT3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--juFNlruK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1656880352238/-ZBKdpkT3.png" alt="Screenshot from 2022-07-03 23-31-55.png" width="880" height="32"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To check the logs of the container run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker logs $container_id

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To enter into our docker container use the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker exec -it $container_id /bin/sh

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  . 5 Deploy to dockerhub.
&lt;/h3&gt;

&lt;p&gt;To deploy this image to docker hub, we have to run the following commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker build -t node-nest:ndj-1.0 
docker login 
docker push node-nest:ndj-1.0

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have successfully dockerized and deployed our application to Dockerhub.&lt;/p&gt;

&lt;p&gt;Follow for more articles on Docker, Jenkins, AWS and DevOps in general.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
