Setting a Failure Exit Code in a Docker Container

Set a failure exit code in a Docker container when the workflow fails.

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:

Press + to interact
if ! ansible-playbook -i hosts_azure_rm.yml site.yml --vault-password-file .vault;
then
echo "Ansible failed!"
rm .vault
exit 1
else
rm .vault
fi

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
Ansible code deployment for AWS

Add, commit, and push the changes to GitHub.

Press + to interact
# Configure user.email
# Replace <Your email> with the actual email
git config --global user.email "<YourEmail>"
# Configure user.name
# Replace <Your name> with the actual name
git config --global user.name "<YourName>"
git add .
git commit -m 'Added failure exit code to entrypoint.sh'
# push the committed changes
git 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
Ansible code deployment for AWS

Perform the following steps:

  1. Build the Dockerfile of your choice and push it to DockerHub. Replace the <Cloud-Provider> with either:
    • AWS
    • Azure
    • Multi-Cloud
Press + to interact
# 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-Cloud
docker build -t <DockerHub-UserName>/ansible:latest .github/actions/ansible/Dockerfiles/<Cloud-Provider>/Dockerfile
  1. Replace <DockerHub-UserName> with your DockerHub username. Push the image to DockerHub.
Press + to interact
# replace <DockerHub-UserName> with your actual username.
docker push <DockerHub-UserName>/ansible:latest
  1. Add, commit, and push the changes to GitHub.
Press + to interact
# Configure user.email
# Replace <Your email> with the actual email
git config --global user.email "<YourEmail>"
# Configure user.name
# Replace <Your name> with the actual name
git config --global user.name "<YourName>"
git add .
git commit -m 'updated base layer'
# push the committed changes
git push
  1. 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.

  1. Open .github/workflows/deploy_ansible.yml.
  2. Add the build job from the lint workflow before the deploy job.

You can review the .github/workflows/lint.yml and .github/workflows/deploy_ansible.yml for the build and deploy jobs, respectively.

  1. Add needs: build to the deploy job.
  2. Delete .github/workflows/lint.yml.
  3. Add, commit, and push the changes.

Solution
The solution to this challenge is provided in the Solution directory. Try it yourself first and compare your solution with the provided solution.

Press + to interact
# Configure user.email
# Replace <Your email> with the actual email
git config --global user.email "<YourEmail>"
# Configure user.name
# Replace <Your name> with the actual name
git config --global user.name "<YourName>"
git add .
git commit -m 'combined workflows'
# push the committed changes
git 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 }}
Combine the workflows - deploy ansible and lint.

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.