Are you currently learning about DevOps? So you must have heard about CI/CD right? But are you the one of those who are confused about it? Then, you are not alone :)
Last time, I've published Getting Started With Jenkins series. Today I come back with an idea to learn about basic CI for beginner (like me) and I'll give you an example of simple task that we can do to get started. Maybe it's a common use case but I saw many people make it harder by combining it with Go, Node.js and many more. So here I just make it to be easier to understand. Before that, let me show you what Continuous Integration is!
CI is a practice where we commit code changes into a repository or project (can be in GitHub or GitLab for example), then it will trigger an automated sequence to build and test of each change.
Now, let's make it to be simple! Here's the scenario:
- Upload Dockerfile to the repository
- Create the workflows to build a Docker image and post it to Docker Hub or Registry
- Run the workflows
We also need GitHub/GitLab account and Docker Hub account.
(Click the link to sign up if you don't have yet)
I'll do the same task above with GitHub Actions and GitLab CI/CD. We'll see the differences as well. So, let's get started!
GitHub Actions
1. Prepare the files
- Dockerfile
FROM nurulramadhona/httpd:v1
COPY index.html /usr/local/apache2/htdocs
EXPOSE 80
- index.html
<html><body><h1>LEARNING GITHUB ACTIONS</h1></body></html>
- docker-test
As an additional task, I've created a bash script named docker-test to create a docker container from the built docker image and get the output.
#!/bin/bash
docker container create --name web-server -p 8080:80 httpd:github
docker container start web-server
curl http://localhost:8080
2. Create a new repository and push the files to your repository
(You can create via web browser if you haven't installed gh CLI)
$ gh repo create learn-ci --public --clone
✓ Created repository nurulramadhona/learn-ci on GitHub
Initialized empty Git repository in /media/nurulramadhona/ops/repo/learn-ci/.git/
$ cd learn-ci/
$ gh repo list --visibility=public | grep learn-ci
nurulramadhona/learn-ci public 2022-07-15T11:18:54Z
$ cd learn-ci/
/learn-ci$ vim index.html
/learn-ci$ vim Dockerfile
/learn-ci$ vim ./docker-test
/learn-ci$ git add .
/learn-ci$ git commit -m "upload docker files"
[master (root-commit) 5ec7453] upload docker files
3 files changed, 8 insertions(+)
create mode 100644 Dockerfile
create mode 100644 docker-test
create mode 100644 index.html
/learn-ci$ git branch -M main
/learn-ci$ git push origin main
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 2 threads
Compressing objects: 100% (5/5), done.
Writing objects: 100% (5/5), 542 bytes | 135.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0)
To github.com:nurulramadhona/learn-ci.git
* [new branch] main -> main
3. Create Workflows
Go to the GitHub page via web browser and switch to the Actions menu. There you'll see a list of provided workflows templates. Here I'll use the one to build and push Docker image but I'll add some additional tasks like below:
- docker-image.yml
name: Docker Image CI
on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build the Docker image
run: docker build . --file Dockerfile --tag httpd:github
- name: Bash script permission
run: chmod +x ./docker-test
- name: Run bash script
run: ./docker-test
- name: Login to DockerHub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v3
with:
push: true
tags: nurulramadhona/httpd:github
on
to define an event, every single thing that happened in/out of the repository.
jobs
to define the sequence of tasks, what have to do.
runs-on
to define the runner environment.
4. Set the value for each variable
As you can see, there are two variables and we need to define them. Switch to Settings menu, then find Secrets under Security. Enter the values for your Docker Hub username and password.
Now, we're ready to commit and run the workflows!
See the workflows! Red means fail and green means success.
That's the example of failed workflows when I made a typo and turned into green when I fixed it.
Here's the sample output of what the GitHub Actions has done.
5. Check the image on Docker Hub
The image is pushed and already exist on my registry. Let's see if it'll work on our localhost!
/learn-ci$ docker container create --name web-github -p 8081:80 nurulramadhona/httpd:github
Unable to find image 'nurulramadhona/httpd:github' locally
github: Pulling from nurulramadhona/httpd
a330b6cecb98: Already exists
14e3dd65f04d: Already exists
fe59ad2e7efe: Already exists
68eb42ff9345: Already exists
9d5052bb82be: Already exists
2197b58d1db7: Already exists
a1a818bde354: Pull complete
Digest: sha256:09860b29e1644d4ecbc8ce61364c40dda0e9e16e0c1ad1eb77ab8b80b453b165
Status: Downloaded newer image for nurulramadhona/httpd:github
e3f99f246acbe720456cfb237ed21b585cc5714f83f2d5db3f62adb029da45b7
/learn-ci$ docker container start web-github
web-github
/learn-ci$ curl localhost:8081
<html><body><h1>LEARNING GITHUB ACTIONS</h1></body></html>
GitLab CI/CD
1. Prepare the files
You can download here.
- Dockerfile
FROM nurulramadhona/httpd:v1
COPY index.html /usr/local/apache2/htdocs
EXPOSE 80
- index.html
<html><body><h1>LEARNING GITLAB CI</h1></body></html>
2. Create a new project and push the file to your project
(Please create the project via web browser and clone it)
/gitlab$ git clone git@gitlab.com:nurulramadhona/learn-ci.git
Cloning into 'learn-ci'...
warning: You appear to have cloned an empty repository.
/gitlab$ cd learn-ci/
/gitlab/learn-ci$ git switch -c main
Switched to a new branch 'main'
/gitlab/learn-ci$ vim Dockerfile
/gitlab/learn-ci$ vim index.html
/gitlab/learn-ci$ git add .
/gitlab/learn-ci$ git commit -m "upload docker files"
[master (root-commit) 311f555] upload docker files
2 files changed, 4 insertions(+)
create mode 100644 Dockerfile
create mode 100644 index.html
/gitlab/learn-ci$ git push origin main
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 2 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 394 bytes | 131.00 KiB/s, done.
Total 4 (delta 0), reused 0 (delta 0)
To gitlab.com:nurulramadhona/learn-ci.git
* [new branch] main -> main
3. Create Pipelines
Create a new file named .gitlab-ci.yml or go to Editor menu under CICD, then put the code below.
stages:
- build
build-job:
stage: build
image: docker:latest
services:
- name: docker:dind
script:
- docker build . --file Dockerfile --tag httpd:gitlab
before_script:
- docker login -u "$CI_REGISTRY_USER" -p "$CI_REGISTRY_PASSWORD" $CI_REGISTRY
script:
- docker build --pull -t "$CI_REGISTRY_IMAGE" .
- docker push "$CI_REGISTRY_IMAGE"
stages
to define how many stage will be used.
image
to define the image will be used to run the scripts.
script
to define the commands in every job/stage.
before script
to define the commands to be executed before script
.
4. Set the value for each variable
As you can see, there are four variables and we need to define them. Switch to Settings => CI/CD, then expand Variables. Enter the values for your Docker Hub username and password.
The additional things to add compared to GitHub Actions:
CI_REGISTRY
= docker.io
CI_REGISTRY_IMAGE
= index.docker.io/username/image:tag
By default, the variable goes to GitLab Registry. So, we need to change them to go to our Docker Registry.
Note*: Don't forget to add tag if you don't want to make it as latest version!
Now, we're ready to commit and run the job! Failed means fail and passed means success.
That's the example of failed jobs when I used wrong image tag by using /
instead of :
. Then, it turned into passed again when I fixed it.
5. Check the image on Docker Hub
The image is pushed and already exist on my registry. Let's see if it'll work on our localhost!
/learn-ci$ docker container create --name web-gitlab-2 -p 8083:80 nurulramadhona/httpd:gitlab
Unable to find image 'nurulramadhona/httpd:gitlab' locally
gitlab: Pulling from nurulramadhona/httpd
a330b6cecb98: Already exists
14e3dd65f04d: Already exists
fe59ad2e7efe: Already exists
68eb42ff9345: Already exists
9d5052bb82be: Already exists
2197b58d1db7: Already exists
5b35b4b65a23: Pull complete
Digest: sha256:a0fde1e9823cb0ab6f604e59c4947cb5ed1035f1fecc921561cfcd4723cfdd6b
Status: Downloaded newer image for nurulramadhona/httpd:gitlab
dcc9222dcff7f2a0ef1a6e4170e6a82a75fdbce8ac44588f52d2c40fc530b2ae
/learn-ci$ docker container start web-gitlab-2
web-gitlab-2
/learn-ci$ curl localhost:8083
<html><body><h1>LEARNING GITLAB CI</h1></body></html>
Alright, that's it for now! Any feedback are very welcome and thank you for coming. Follow me to get notified when new post is published by me! Thank you.
References:
Top comments (2)
That's a great article to understand CI concepts.
Thank you @jatin