Setting a Failure Exit Code in a Docker Container
Set a failure exit code in a Docker container when the workflow fails.
We'll cover the following
When the workflow failed to get the vault password, the build returned a green checkmark. It did not accurately return the Ansible failure. Without an accurate build status, you won’t know what or when to troubleshoot.
You fix this issue by setting failure exit codes in the Docker container. There are many ways to go about it, but a simple solution is to add an if
statement to the entrypoint.sh
.
Review the if
statement below:
if ! ansible-playbook -i hosts_azure_rm.yml site.yml --vault-password-file .vault;thenecho "Ansible failed!"rm .vaultexit 1elserm .vaultfi
The entrypoint.sh
now echoes Ansible failed! And throws an exit code of 1
when the ansible-playbook
does not exit with a 0
. This is enough for the Github workflow to report an accurate build status.
Update the <dynamic-inventory>
with the dynamic inventory of the cloud provider of your choice in the entrypoint.sh
file.
Open site.yml
and remove the indentation for line 2.
- name: '[Linux] configure ngnix' import_playbook: configure_nginx_web_server.yml - hosts: windows gather_facts: false vars: ansible_connection: winrm ansible_winrm_transport: ntlm ansible_winrm_server_cert_validation: ignore roles: - chocolatey - name: '[Windows] configure IIS' import_playbook: configure_iis_web_server.yml
Add, commit, and push the changes to GitHub.
# Configure user.email# Replace <Your email> with the actual emailgit config --global user.email "<YourEmail>"# Configure user.name# Replace <Your name> with the actual namegit config --global user.name "<YourName>"git add .git commit -m 'Added failure exit code to entrypoint.sh'# push the committed changesgit push
Log into GitHub and review the latest run of the workflow. You’ll see the build status returned with a red x, as expected.
Correct the indentation on line 2 of the site.yml
before moving on. Run
the widget and add, commit, and push the changes to Github again.
Use a base image
Notice that the deploy Ansible workflow takes a while. The reason is the Dockerfile.
Each time the workflow runs, it calls the Docker container action that you created. That action builds the Dockerfile and prepares the container for the workflow. The container is pretty big, so it will take a while. By improving the container, you can reduce the build time.
You will update the action to use a new base layer, our base layer.
You can push an image to DockerHub and use that image as Your GitHub action base. The benefit is, when the action runs, it won’t build the entire image, drastically reducing build time.
Within your Ansible
repository, we have created a directory called Dockerfiles
.
In that directory, we have created a new Dockerfile, copied all the contents of
./github/actions/ansible/Dockerfile
except the COPY
and ENTRYPOINT
commands.
Replace <DockerHub-UserName>
with your Dockerhub username.
Cloud Provider specific Dockerfile
You can use the Dockerfile that meets the requirements of the cloud provider of your choice.
Review the Dockerfiles
directory below:
FROM ubuntu:latest RUN apt-get update && apt-get install -y curl && apt-get install -y wget RUN apt-get install -y git RUN apt-get install -y inotify-tools RUN apt-get install -y nano tree vim jq RUN apt-get update; \ apt install -y python3-pip; \ apt install -y sshpass; \ apt install -y openssh-client; \ apt-get install -y ipt-transport-https; \ wget -q https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb;\ dpkg -i packages-microsoft-prod.deb; \ apt-get update; \ add-apt-repository universe; \ apt-get install -y powershell; \ pwsh -c "Set-PackageSource -Name PSGallery -Trusted"; \ pwsh -c "Install-Module AZ -Scope AllUsers"; RUN curl -sL https://aka.ms/InstallAzureCLIDeb | bash ; RUN pip3 install --upgrade pip; \ pip3 install "ansible==2.9.12"; \ pip3 install boto; \ pip3 install boto3; \ pip3 install "pywinrm>=0.3.0"; \ pip3 install ansible[azure]; \ pip3 install ansible-lint
Perform the following steps:
- Build the Dockerfile of your choice and push it to DockerHub. Replace the
<Cloud-Provider>
with either:- AWS
- Azure
- Multi-Cloud
# Upload the Image to DockerHub# replace <DockerHub-UserName> with your actual username.docker login --username <DockerHub-UserName># Add a repository name to the tag# Replace the <Cloud-Provider> with the either AWS, Azure or Multi-Clouddocker build -t <DockerHub-UserName>/ansible:latest .github/actions/ansible/Dockerfiles/<Cloud-Provider>/Dockerfile
- Replace
<DockerHub-UserName>
with your DockerHub username. Push the image to DockerHub.
# replace <DockerHub-UserName> with your actual username.docker push <DockerHub-UserName>/ansible:latest
- Add, commit, and push the changes to GitHub.
# Configure user.email# Replace <Your email> with the actual emailgit config --global user.email "<YourEmail>"# Configure user.name# Replace <Your name> with the actual namegit config --global user.name "<YourName>"git add .git commit -m 'updated base layer'# push the committed changesgit push
- Log into GitHub and review the workflow output.
Notice the time that the job takes now.
Try it now
At the moment, Ansible lint and deploy Ansible are two different workflows.
Combine lint and deploy into a single workflow
In a release pipeline, you want to prevent deploying code if linting fails. So, you need to combine the two workflows into one.
Add Ansible lint to the deploy ansible workflow.
- Open
.github/workflows/deploy_ansible.yml
. - Add the
build
job from the lint workflow before thedeploy
job.
You can review the
.github/workflows/lint.yml
and.github/workflows/deploy_ansible.yml
for the build and deploy jobs, respectively.
- Add
needs: build
to thedeploy
job. - Delete
.github/workflows/lint.yml
. - Add, commit, and push the changes.
Solution
The solution to this challenge is provided in theSolution
directory. Try it yourself first and compare your solution with the provided solution.
# Configure user.email# Replace <Your email> with the actual emailgit config --global user.email "<YourEmail>"# Configure user.name# Replace <Your name> with the actual namegit config --global user.name "<YourName>"git add .git commit -m 'combined workflows'# push the committed changesgit push
name: deploy ansible on: push: branches: - master pull_request: branches: - master jobs: build: runs-on: ubuntu-latest steps: - name: checkout repo uses: actions/checkout@v2 - name: Lint Ansible Playbook uses: ansible/ansible-lint-action@master env: ANSIBLE_VAULT_PASSWORD: ${{ secrets.ANSIBLE_VAULT_PASSWORD }} with: targets: "" deploy: needs: build runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - uses: ./.github/actions/ansible with: inventory: hosts_azure_rm.yml env: ANSIBLE_VAULT_PASSWORD: ${{ secrets.ANSIBLE_VAULT_PASSWORD }} AZURE_TENANT: ${{ secrets.AZURE_TENANT }} AZURE_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} AZURE_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} AZURE_SECRET: ${{ secrets.AZURE_SECRET }}
In this lesson, we introduced failure exit code, how you can reduce the execution time of your workflows, and how to combine the two workflows, deploy ansible and lint.
Get hands-on with 1300+ tech skills courses.