Migrated Yet Again

I didn’t feel right that I had to clone the boot volume and recreated the blog instance out of it to recover my SSH key, so I created an ARM instance from scratch again.

It was very easy to install and configure the Docker containers this time because I already had an Ansible project to automate it.

If you are seeing this article, you are seeing it on a yet another ARM host with Dockerized WordPress.

Ansible WordPress Repo

I guess I finished my personal project of provisioning WordPress site with Ansible. I was able to run it and get a WordPress site to show up in just about 10 mins. I’m sure there are some loose end I could tighten but it generally works. Here is the GitHub repo I worked on.

ansible-wordpress repo on GitHub

Setting up a free OCI account (ARM64 Oracle Linux 8 is always free eligible) and getting a domain name through dnsimple.com are two things you may need to do but if you pay like $60 for dnsimple.com (DNS service) annually, you get to have your own full blown WordPress site with your own domain name.

One thing to be careful about this approach is that you have the full control over the site, meaning if there is any issue, you are on your own to analyze and resolve the issue. You have to update your SSL cert yourself as well. If you are not so good with Linux or have no willingness to dig into it, it wouldn’t be for you.

If you are a CS student wanting your own site or you are learning how websites work, you may want to dig into it. After all, just $60 per year to have your own WordPress site with your own domain name is really reasonable.

Full WordPress Site within 10 Mins

I pretty much finished writing the Ansible code to configure an Oracle Linux 8 machine from scratch to the point where it runs a full WordPress site on ARM64 processor. It took just about 10 mins. This is a milestone for me. It used to take at least a few hours for me to set it up when I didn’t have Ansible automation while I search for the information I blogged here.

I will probably polish the code to the point where I can share with the community sometime this week or next week.

WordPress Site with Ansible

This site is served on Oracle Linux 7 (ARM64) and Docker containers of WordPress, NGINX, Maria DB and phpMyAdmin. Since the time when I figured out how to have WordPress on Docker on a Linux host, I have configured this site manually multiple times. It’s not crazy hard but it’s still some work.

I thought about automating it but I just didn’t have a chance. Now that I’ve been learning Ansible, I feel I can make that happen. Just execute a command and it will automatically configure a WordPress site wherever your host is.

I’m starting a repo on GitHub. I will be pushing what I come up with.

MySQL 8 Community Edition on Vagrant VM

As I mentioned in my previous blog, I have been working on a personal project that allows us to provision a test Vagrant VM that has MySQL 8 Community Edition installed. The combination between Vagrant and Ansible made this possible.

I put the code up in GitHub for your consumption and feedback.

When you do vagrant init [url], it creates Vagrantfile. The Vagrantfile has the configuration of the Vagrant VM. You can have Ansible file in the Vagrant file to automatically execute when the Vagrant VM starts.

So yeah, please read the README file to start to use it. Any feedback and pull requests are welcome! 🙂

How to Install Docker Engine with Ansible on Oracle Linux 7

I am wanting to make sure Docker engine is present on my Jenkins host. To prove that Docker is not installed yet, here is the result of sudo systemctl status docker on the Jenkins host.

Unit docker.service could not be found.

Here is the Ansible playbook I came up with. The target host is an Oracle Linux 7 on ARM64 processor.

- name: Install docker
  gather_facts: No
  hosts: jenkins

    - name: Install Docker
        name: docker-engine
        state: installed
      become: yes
    - name: Enable/Start Docker
        name: docker
        enabled: yes
        state: started
      become: yes

    - name: Add user vagrant to docker group
        name: vagrant
        groups: docker
        append: yes
      become: yes

Here is the result when I execute it.

ansible-playbook playbooks/docker-ce.yaml
PLAY [Install docker] ****************************************************************************************************************************

TASK [Install Docker] ****************************************************************************************************************************
changed: [jenkins.hayato-iriumi.net]

TASK [Enable/Start Docker] ***********************************************************************************************************************
changed: [jenkins.hayato-iriumi.net]

TASK [Add user vagrant to docker group] **********************************************************************************************************
ok: [jenkins.hayato-iriumi.net]

PLAY RECAP ***************************************************************************************************************************************
jenkins.hayato-iriumi.net  : ok=3    changed=2    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

When I ssh into the Jenkins host and check if Docker daemon is running here is the output.

[opc@jenkins ~]$ sudo systemctl status docker
● docker.service - Docker Application Container Engine
   Loaded: loaded (/usr/lib/systemd/system/docker.service; enabled; vendor preset: disabled)
   Active: active (running) since Mon 2022-01-03 04:55:11 GMT; 1min 37s ago
     Docs: https://docs.docker.com
 Main PID: 18476 (dockerd)
    Tasks: 8
   Memory: 37.5M
   CGroup: /system.slice/docker.service
           └─18476 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock

Jan 03 04:55:10 jenkins dockerd[18476]: time="2022-01-03T04:55:10.694835968Z" level=warning msg="Your kernel does not support cgroup blkio weight"
Jan 03 04:55:10 jenkins dockerd[18476]: time="2022-01-03T04:55:10.695237969Z" level=warning msg="Your kernel does not support cgroup bl..._device"
Jan 03 04:55:10 jenkins dockerd[18476]: time="2022-01-03T04:55:10.695923611Z" level=info msg="Loading containers: start."
Jan 03 04:55:11 jenkins dockerd[18476]: time="2022-01-03T04:55:11.014165992Z" level=info msg="Default bridge (docker0) is assigned with...address"
Jan 03 04:55:11 jenkins dockerd[18476]: time="2022-01-03T04:55:11.130298822Z" level=info msg="Loading containers: done."
Jan 03 04:55:11 jenkins dockerd[18476]: time="2022-01-03T04:55:11.147750103Z" level=warning msg="Not using native diff for overlay2, th...overlay2
Jan 03 04:55:11 jenkins dockerd[18476]: time="2022-01-03T04:55:11.148281344Z" level=info msg="Docker daemon" commit=9bb540d graphdriver...03.11-ol
Jan 03 04:55:11 jenkins dockerd[18476]: time="2022-01-03T04:55:11.148597025Z" level=info msg="Daemon has completed initialization"
Jan 03 04:55:11 jenkins systemd[1]: Started Docker Application Container Engine.
Jan 03 04:55:11 jenkins dockerd[18476]: time="2022-01-03T04:55:11.208274084Z" level=info msg="API listen on /var/run/docker.sock"
Hint: Some lines were ellipsized, use -l to show in full.

Contained Ansible Environment

When installing Ansible on Linux, ansible.cfg and hosts files are at /etc/ansible. Instead of changing the files there, I am going to create a more contained Ansible environment.

I am doing this because of the following 3 reasons.

  • The configuration and host list does not get affected by external changes.
  • The changes can be traced with source control like Git.
  • The changes can be reviewed by your peers for any error.

Let’s create the ansible.cfg file.

ansible-config init --disabled -t all > ansible.cfg

Now I am going to create hosts file in the same directory with the following content.

jenkins.hayato-iriumi.net ansible_user=opc
ansibletest.westcentralus.cloudapp.azure.com ansible_user=azureuser

Now add or uncomment the following line in ansible.cfg file.


Test run.

ansible all -m ping

As long as you can access those hosts from your ssh, the command should be successful.

ansibletest.westcentralus.cloudapp.azure.com | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/libexec/platform-python"
    "changed": false,
    "ping": "pong"
jenkins.hayato-iriumi.net | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    "changed": false,
    "ping": "pong"

How to do sudo with Ansible

Now I have the following content in my test.yaml playbook. I want Ansible to write a file under /etc directory.

- name: My playbook
  hosts: test
     - name: Leaving a mark
       command: "touch /etc/foo"

When I execute it like the following, I get an error.

ansible-playbook-3 test.yaml
fatal: [ansibletest.westcentralus.cloudapp.azure.com]: FAILED! => {"changed": true, "cmd": ["touch", "/etc/foo"], "delta": "0:00:00.003802", "end": "2022-01-01 02:53:01.519156", "msg": "non-zero return code", "rc": 1, "start": "2022-01-01 02:53:01.515354", "stderr": "touch: cannot touch '/etc/foo': Permission denied", "stderr_lines": ["touch: cannot touch '/etc/foo': Permission denied"], "stdout": "", "stdout_lines": []}

Obviously, azureuser does not have permission to write out the file, so how do we do sudo in Ansible?

You just have to pass --become parameter to do sudo in Ansible.

ansible-playbook-3 test.yaml --become
PLAY [My playbook] *******************************************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************************************************
ok: [ansibletest.westcentralus.cloudapp.azure.com]

TASK [Leaving a mark] ****************************************************************************************************************************
[WARNING]: Consider using the file module with state=touch rather than running 'touch'.  If you need to use command because file is insufficient
you can add 'warn: false' to this command task or set 'command_warnings=False' in ansible.cfg to get rid of this message.
changed: [ansibletest.westcentralus.cloudapp.azure.com]

PLAY RECAP ***************************************************************************************************************************************
ansibletest.westcentralus.cloudapp.azure.com : ok=2    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

After executing it, I checked the file and it was created.

How to Dry Run Ansible Playbook

I have test.yaml playbook with the following content.

- name: My playbook
  hosts: all
     - name: Leaving a mark
       command: "touch /tmp/ansible_was_here"

I would like to do dry run using this playbook. Here is what I can do.

ansible-playbook-3 test.yaml --check

Here is the output.

[opc@ansible-primary ansible]$ ansible-playbook-3 test.yaml --check

PLAY [My playbook] *******************************************************************************************************************************

TASK [Gathering Facts] ***************************************************************************************************************************
[WARNING]: Platform linux on host jenkins.pub.ashburn.oraclevcn.com is using the discovered Python interpreter at /usr/bin/python, but future
installation of another Python interpreter could change this. See
https://docs.ansible.com/ansible/2.9/reference_appendices/interpreter_discovery.html for more information.
ok: [jenkins.pub.ashburn.oraclevcn.com]
ok: [ansibletest.westcentralus.cloudapp.azure.com]

TASK [Leaving a mark] ****************************************************************************************************************************
skipping: [jenkins.pub.ashburn.oraclevcn.com]
skipping: [ansibletest.westcentralus.cloudapp.azure.com]

PLAY RECAP ***************************************************************************************************************************************
ansibletest.westcentralus.cloudapp.azure.com : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0
jenkins.pub.ashburn.oraclevcn.com : ok=1    changed=0    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

It skipped the actual execution on the hosts specified in /etc/ansbile/hosts and returned ok for each host.