This repo provides a guide ๐ to creating a simple pipeline to build โ and upload docker ๐ณ image artifacts to the docker hub ๐ณ repo with the help of GitHub actions as changes take place in GitHub main branch.
-
Docker ๐ณ basics.
-
Yaml ๐ basics
If you are viewing this page from GitHub pages then some code for GitHub secrets will not be shown, you will only see a $ sign. Check out GitHub repo from ๐Here for the correct code.
For this demo, the application is to be dockerized ๐ณ in a static site. It is a simple game of guessing ๐ค numbers between 0 0๏ธโฃ to 9 9๏ธโฃ. You access this page Here
/src
index.html
index.css
/Dockerfile
/README.md
Let's take a look ๐ at source files ๐
/src
- This folder contains source files ๐ for our static site.Dockerfile
- This is a basic Dockerfile ๐ณ which specifies how the image should be built from the source. We will take a look ๐ at this in a moment.README.md
- This is the file ๐ you currently reading.
Dockerfile ๐ณ provides a set of instuctions to build โ the image. For this repo it looks ๐ like the following.
FROM nginx
ADD src/* /usr/share/nginx/html/
EXPOSE 80
CMD ["nginx","-g","daemon off;"]
Let's take a look ๐ at each instruction to understand what these instructions mean
FROM nginx
- This line tells docker ๐ณ to use Nginx ๐ as the official image as a base image for our new image.ADD src/* /usr/share/nginx/html/
- This line copies files ๐ ofsrc
folder inside the/usr/share/nginx/html/
folder of image./usr/share/nginx/html/
folder is used by the nginx ๐ server as entry point of website.EXPOSE 80
- This line tells docker ๐ณ to open port 80 inside the docker ๐ณ container so that we can communicate with the nginx ๐ server inside.CMD ["nginx","-g","daemon off;"]
- This last cline starts Nginx ๐ server and runs โถ every time the docker ๐ณ container start.
It's all about what we need to get started. Let's take a look ๐ how to setup GitHub actions to create a pipeline.
- Open github repo and click on actions option.
- Search ๐ for Simple workflow and select the most suitable from the option that appeared.
- Rename the file ๐ with the name you want for your workflow.
-
Replace ๐ the code ๐ฉโ๐ป of workflow with the following.
name: on: jobs:
Let's understand ๐ค what this code ๐ฉโ๐ป means
- The lines starting with # represents comments in YAML.
name:
- Defines the name for your workflow.on:
- When we create a GitHub action, we want the action to run โถ on certain events i.e push to a branch. Thison
parameter describes the events in which the action is going to run โถ.jobs:
- jobs work section is the place where we define what going to happen when events specified in theon:
section occurs.
-
Give a name to your workflow
name: Docker image CI
-
Specify the event of our interest in this case push event
-
Add event
name: Docker image CI on: push:
-
Add branches for which we going to perform some action
name: Docker image CI on: push: branches: [ "main" ]
-
-
Now the remaining part of the workflow is jobs section. Jobs define the set of actions (Tasks) to be performed. These action can run โถ sequentially or in parallel. for this demo we are just going to create one job named docker-build.
name: Docker image CI on: push: branches: [ "main" ] jobs: docker-build:
-
Each job section has following things
-
runs-on:
- Tells ๐ข the platform on which this job(Task) is going to run โถ on. For this demo, we are taking 'ubuntu-latest'. -
steps:
- This defines a set of steps to be performed to get the job done. -
Now our code ๐ฉโ๐ป will look ๐ like this.
name: Docker image CI on: push: branches: [ "main" ] jobs: docker-build: runs-on: ubuntu-latest steps:
Each step in steps walk section has the following parts
name:
- name of the steprun:
- set of command ๐ป to run โถuses:
- rerefence of any other action which is used by the current steps. The referenced action will run โถ first.optional
- Apart from these, there are many other optional parts.
-
-
Add the following code ๐จโ๐ป in the steps section
- uses: actions/checkout@v3 - name: Build the Docker image run: |
- notice
|
afterrun:
this allows us to write multiple commands ๐ป.
- notice
-
To build โ image add the following command ๐ป to the
Build the Docker image
step and replace<image_name>
With the name of your choice.docker build . --file Dockerfile --tag <image_name>
-
Now our file ๐ look ๐ something like this
name: Docker image CI on: push: branches: [ "main" ] jobs: docker-build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Build the Docker image run: | docker build . --file Dockerfile --tag hackthenumber
-
Notice ๐ the uses part specifies
actions/checkout@v3
. This action checks if our repository is present and if we have access to it. -
Command ๐ป
docker build . --file Dockerfile --tag hackthenumber
builds โ an image named hackthenumber it is currently stored at the local system at which the job is running.
-
-
Login ๐ to dockerhub ๐ณ
To make push the image to the docker hub ๐ณ we need to login to the docker hub ๐ณ. Docker recommends creating access tokens for logins ๐ instead of using password ๐.
-
Creating dockerhub ๐ณ Access token ๐
-
Adding passwords ๐ directly to workflow files ๐ can be a potential threat. To make this secure GitHub provides secrets to store passwords ๐ etc. To add the secrets to GitHub repo do the following.
- Goto your repo.
- Open Settings ๐ง.
- Select
Secret > Actions > New Repository Secret
- Add DOCKERHUB as name and your docker hub username as secret.
- Add another secret for TOKEN as the name and paste the access token you generated โ in the previous step.
-
Login ๐ to Dockerhub ๐ณ
-
Add the following lines to run part to login ๐
docker login -u ${{secrets.USERNAME}} -p ${{secrets.TOKEN}}
-
-
-
Tag image to refer to Dockerhub ๐ณ repo
-
To tag image add the following command ๐ป by replacing
<image_name>
with the image name you have choosen for your imagedocker tag <image_name> ${{secrets.USERNAME}}/<image_name>
-
With our choosen name it will look ๐ like something this
docker tag hackthenumber ${{secrets.USERNAME}}/hackthenumber
-
-
Add the following line to push image to dockerhub ๐ณ
docker push ${{secrets.USERNAME}}/hackthenumber
Now our file ๐ will look ๐ like something this
name: Docker image CI
on:
push:
branches: [ "main" ]
jobs:
docker-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build the Docker image
run: |
docker build . --file Dockerfile --tag hackthenumber
docker login -u ${{secrets.USERNAME}} -p ${{secrets.TOKEN}}
docker tag hackthenumber ${{secrets.USERNAME}}/hackthenumber
docker push ${{secrets.USERNAME}}/hackthenumber
Similarly, you can add code to test if everything is working fine in the same script. After adding the testing code, our final code will look like this.
name: Docker image CI
on:
push:
branches: [ "main" ]
jobs:
docker-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build the Docker image
run: |
docker build . --file Dockerfile --tag hackthenumber
docker login -u ${{secrets.USERNAME}} -p ${{secrets.TOKEN}}
docker tag hackthenumber ${{secrets.USERNAME}}/hackthenumber
docker-test:
runs-on: ubuntu-latest
needs: docker-build
steps:
- uses: actions/checkout@v3
- name: Test image presence
run: |
docker image inspect ${{secrets.USERNAME}}/hackthenumber
if [[ $? -eq 1 ]]; then
echo "โ Image not found!"
exit 1 # This will cause the job to fail
else
echo "โ
Image Build Successfully!"
fi
- name: Test image response
run: |
docker run -itdp 8000:80 --rm ${{secrets.USERNAME}}/hackthenumber
response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:8000)
if [[ $response -ne 200 ]]; then
echo "โ Image response is not 200!"
exit 1
else
echo "โ
Image response is 200!"
fi
docker-deploy:
runs-on: ubuntu-latest
needs: docker-test
steps:
- uses: actions/checkout@v3
- name: Deploy to docker hub
run: |
docker push ${{secrets.USERNAME}}/hackthenumber && echo "โ
Deployed to Docker Hub" || echo "โ Deployment to Docker Hub failed"
-
Go to https://labs.play-with-docker.com and login ๐ with dockerhub ๐ณ credentials.
-
Click start and then Add New Instance.
-
Run โ the command ๐ป
docker run -dp 8080:80 <username>/<image_name>
by replacing<username>
with the dockerhub username and<image_name>
with the image name used in the GitHub action. For exampledocker run -dp 8080:80 sandeepsource/hackthenumber
-
Click the port number
8080
on the right side of the open port button. If the button for port8080
not appeared then click theopen port
button and enter 8080 and click ok. -
Now if everything is gone well ๐ you will able to see following output.