This post is about Ansible Server Provisioning
Introduction
From bare metal through function-as-a-service, automating with ansible server provisioning of infrastructure is the first step in automating the operation of your applications. Ansible can provision from cloud platforms and virtualized hosts to hypervisors, network devices, and bare-metal servers.
Bootstrapping the nodes can be connected to storage, added to a load balancer, security patched, or any other operational tasks by separate teams. So, Ansible becomes the connecting tool in any of your process pipelines – automatically taking basic infrastructure right through to day-to-day management.
Ansible server provisioning Role with Defaults
We’ll start with an Ansible role called hello_web that will install an Apache web server on Centos and have Vagrant bring up the guest system and run the tasks in the role.
Initial Work Area Structure
# mkdir provision-unixcop
# cd provision-unixcop/
# mkdir roles
# ansible-galaxy init roles/provision-unixcop
Vagrant Configuration Ansible Server Provisoning
Now we need to create our Vagrant configuration with this Vagrantfile:
cat Vagrantfile
Vagrant.configure("2") do |config|
config.vm.box = "geerlingguy/centos7"
config.vm.network "forwarded_port", guest: 80, host: 8080
####### Provision #######
config.vm.provision "ansible_local" do |ansible|
ansible.playbook = "apply_provision.yml"
ansible.verbose = true
end
end
The ansible_local provisioner defaults are adequate for our simple role provision-unixcop. The site playbook or the playbook that runs our desired roles for this guest system is called playbook.yml. This will kick off everything we need to make this work.
Create the Playbook
The provisioner picks a playbook to run for the provisioning process. This is where we can select the provision-unixcop role. Update provision/playbook.yml with this:
cat apply_provision.yml
---
- hosts: all
become: true
roles:
- roles/provision-unixcop
Create the Role Defaults
Now we can start digging into the role parts. But, first, let’s set some default variables with defaults that make sense for a Centos system. From within the provision-unixcop role, update tasks/main.yml with this:
cat roles/provision-unixcop/tasks/main.yml
---
# tasks file for role/provision-unixcop
- name: Install Apache
yum:
name: httpd
state: present
- shell: |
echo " <html>" > /var/www/html/index.html
echo "<body>" >> /var/www/html/index.html
echo "<h1>" >> /var/www/html/index.html
echo "Hello UnixCop friends" >> /var/www/html/index.html
echo "</h1>" >> /var/www/html/index.html
echo "</body>" >> /var/www/html/index.html
echo " </html>" >> /var/www/html/index.html
- systemd:
name: httpd
state: started
enabled: true
These tasks use three modules (analogous to resources in Chef and Puppet) of yum, systemd, and shell to create our web server and content, and their purpose should be self-explanatory based on the name value for each task to describe what the job does.
Test provisioning
# vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'geerlingguy/centos7'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'geerlingguy/centos7' version '1.2.26' is up to date...
==> default: Setting the name of the VM: provision-unixcop_default_1657368154853_52472
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
default: Adapter 1: nat
==> default: Forwarding ports...
default: 80 (guest) => 8080 (host) (adapter 1)
default: 22 (guest) => 2222 (host) (adapter 1)
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
default: SSH address: 127.0.0.1:2222
default: SSH username: vagrant
default: SSH auth method: private key
default:
default: Vagrant insecure key detected. Vagrant will automatically replace
default: this with a newly generated keypair for better security.
default:
default: Inserting generated public key within guest...
default: Removing insecure key from the guest if it's present...
default: Key inserted! Disconnecting and reconnecting using new SSH key...
==> default: Machine booted and ready!
==> default: Checking for guest additions in VM...
==> default: Mounting shared folders...
default: /vagrant => /home/neil/provision-unixcop
==> default: Running provisioner: ansible_local...
default: Installing Ansible...
default: Running ansible-playbook...
cd /vagrant && PYTHONUNBUFFERED=1 ANSIBLE_FORCE_COLOR=true ansible-playbook --limit="default" --inventory-file=/tmp/vagrant-ansible/inventory -v apply_provision.yml
Using /etc/ansible/ansible.cfg as config file
PLAY [all] *********************************************************************
TASK [Gathering Facts] *********************************************************
ok: [default]
TASK [roles/provision-unixcop : Install Apache] ********************************
changed: [default] => {"changed": true, "changes": {"installed": ["httpd"]}, "msg": "", "rc": 0, "results": ["Loaded plugins: fastestmirror\nLoading mirror speeds from cached hostfile\n * base: mirror.hostlink.com.hk\n * epel: hkg.mirror.rackspace.com\n * extras: mirror.hostlink.com.hk\n * updates: mirror.hostlink.com.hk\nResolving Dependencies\n--> Running transaction check\n---> Package httpd.x86_64 0:2.4.6-97.el7.centos.5 will be installed\n--> Processing Dependency: httpd-tools = 2.4.6-97.el7.centos.5 for package: httpd-2.4.6-97.el7.centos.5.x86_64\n--> Processing Dependency: /etc/mime.types for package: httpd-2.4.6-97.el7.centos.5.x86_64\n--> Processing Dependency: libaprutil-1.so.0()(64bit) for package: httpd-2.4.6-97.el7.centos.5.x86_64\n--> Processing Dependency: libapr-1.so.0()(64bit) for package: httpd-2.4.6-97.el7.centos.5.x86_64\n--> Running transaction check\n---> Package apr.x86_64 0:1.4.8-7.el7 will be installed\n---> Package apr-util.x86_64 0:1.5.2-6.el7 will be installed\n---> Package httpd-tools.x86_64 0:2.4.6-97.el7.centos.5 will be installed\n---> Package mailcap.noarch 0:2.1.41-2.el7 will be installed\n--> Finished Dependency Resolution\n\nDependencies Resolved\n\n================================================================================\n Package Arch Version Repository Size\n================================================================================\nInstalling:\n httpd x86_64 2.4.6-97.el7.centos.5 updates 2.7 M\nInstalling for dependencies:\n apr x86_64 1.4.8-7.el7 base 104 k\n apr-util x86_64 1.5.2-6.el7 base 92 k\n httpd-tools x86_64 2.4.6-97.el7.centos.5 updates 94 k\n mailcap noarch 2.1.41-2.el7 base 31 k\n\nTransaction Summary\n================================================================================\nInstall 1 Package (+4 Dependent packages)\n\nTotal download size: 3.0 M\nInstalled size: 10 M\nDownloading packages:\n--------------------------------------------------------------------------------\nTotal 957 kB/s | 3.0 MB 00:03 \nRunning transaction check\nRunning transaction test\nTransaction test succeeded\nRunning transaction\n Installing : apr-1.4.8-7.el7.x86_64 1/5 \n Installing : apr-util-1.5.2-6.el7.x86_64 2/5 \n Installing : httpd-tools-2.4.6-97.el7.centos.5.x86_64 3/5 \n Installing : mailcap-2.1.41-2.el7.noarch 4/5 \n Installing : httpd-2.4.6-97.el7.centos.5.x86_64 5/5 \n Verifying : apr-1.4.8-7.el7.x86_64 1/5 \n Verifying : mailcap-2.1.41-2.el7.noarch 2/5 \n Verifying : httpd-tools-2.4.6-97.el7.centos.5.x86_64 3/5 \n Verifying : apr-util-1.5.2-6.el7.x86_64 4/5 \n Verifying : httpd-2.4.6-97.el7.centos.5.x86_64 5/5 \n\nInstalled:\n httpd.x86_64 0:2.4.6-97.el7.centos.5 \n\nDependency Installed:\n apr.x86_64 0:1.4.8-7.el7 apr-util.x86_64 0:1.5.2-6.el7 \n httpd-tools.x86_64 0:2.4.6-97.el7.centos.5 mailcap.noarch 0:2.1.41-2.el7 \n\nComplete!\n"]}
TASK [roles/provision-unixcop : shell] *****************************************
changed: [default] => {"changed": true, "cmd": "echo \" <html>\" > /var/www/html/index.html\necho \"<body>\" >> /var/www/html/index.html\necho \"<h1>\" >> /var/www/html/index.html\necho \"Hello UnixCop friends\" >> /var/www/html/index.html\necho \"</h1>\" >> /var/www/html/index.html\necho \"</body>\" >> /var/www/html/index.html\necho \" </html>\" >> /var/www/html/index.html\n", "delta": "0:00:00.004133", "end": "2022-07-09 12:08:53.281133", "rc": 0, "start": "2022-07-09 12:08:53.277000", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
TASK [roles/provision-unixcop : systemd] ***************************************
changed: [default] => {"changed": true, "enabled": true, "name": "httpd", "state": "started", "status": {"ActiveEnterTimestampMonotonic": "0", "ActiveExitTimestampMonotonic": "0", "ActiveState": "inactive", "After": "systemd-journald.socket basic.target remote-fs.target nss-lookup.target network.target tmp.mount -.mount system.slice", "AllowIsolate": "no", "AmbientCapabilities": "0", "AssertResult": "no", "AssertTimestampMonotonic": "0", "Before": "shutdown.target", "BlockIOAccounting": "no", "BlockIOWeight": "18446744073709551615", "CPUAccounting": "no", "CPUQuotaPerSecUSec": "infinity", "CPUSchedulingPolicy": "0", "CPUSchedulingPriority": "0", "CPUSchedulingResetOnFork": "no", "CPUShares": "18446744073709551615", "CanIsolate": "no", "CanReload": "yes", "CanStart": "yes", "CanStop": "yes", "CapabilityBoundingSet": "18446744073709551615", "CollectMode": "inactive", "ConditionResult": "no", "ConditionTimestampMonotonic": "0", "Conflicts": "shutdown.target", "ControlPID": "0", "DefaultDependencies": "yes", "Delegate": "no", "Description": "The Apache HTTP Server", "DevicePolicy": "auto", "Documentation": "man:httpd(8) man:apachectl(8)", "EnvironmentFile": "/etc/sysconfig/httpd (ignore_errors=no)", "ExecMainCode": "0", "ExecMainExitTimestampMonotonic": "0", "ExecMainPID": "0", "ExecMainStartTimestampMonotonic": "0", "ExecMainStatus": "0", "ExecReload": "{ path=/usr/sbin/httpd ; argv[]=/usr/sbin/httpd $OPTIONS -k graceful ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }", "ExecStart": "{ path=/usr/sbin/httpd ; argv[]=/usr/sbin/httpd $OPTIONS -DFOREGROUND ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }", "ExecStop": "{ path=/bin/kill ; argv[]=/bin/kill -WINCH ${MAINPID} ; ignore_errors=no ; start_time=[n/a] ; stop_time=[n/a] ; pid=0 ; code=(null) ; status=0/0 }", "FailureAction": "none", "FileDescriptorStoreMax": "0", "FragmentPath": "/usr/lib/systemd/system/httpd.service", "GuessMainPID": "yes", "IOScheduling": "0", "Id": "httpd.service", "IgnoreOnIsolate": "no", "IgnoreOnSnapshot": "no", "IgnoreSIGPIPE": "yes", "InactiveEnterTimestampMonotonic": "0", "InactiveExitTimestampMonotonic": "0", "JobTimeoutAction": "none", "JobTimeoutUSec": "0", "KillMode": "control-group", "KillSignal": "18", "LimitAS": "18446744073709551615", "LimitCORE": "18446744073709551615", "LimitCPU": "18446744073709551615", "LimitDATA": "18446744073709551615", "LimitFSIZE": "18446744073709551615", "LimitLOCKS": "18446744073709551615", "LimitMEMLOCK": "65536", "LimitMSGQUEUE": "819200", "LimitNICE": "0", "LimitNOFILE": "4096", "LimitNPROC": "1856", "LimitRSS": "18446744073709551615", "LimitRTPRIO": "0", "LimitRTTIME": "18446744073709551615", "LimitSIGPENDING": "1856", "LimitSTACK": "18446744073709551615", "LoadState": "loaded", "MainPID": "0", "MemoryAccounting": "no", "MemoryCurrent": "18446744073709551615", "MemoryLimit": "18446744073709551615", "MountFlags": "0", "Names": "httpd.service", "NeedDaemonReload": "no", "Nice": "0", "NoNewPrivileges": "no", "NonBlocking": "no", "NotifyAccess": "main", "OOMScoreAdjust": "0", "OnFailureJobMode": "replace", "PermissionsStartOnly": "no", "PrivateDevices": "no", "PrivateNetwork": "no", "PrivateTmp": "yes", "ProtectHome": "no", "ProtectSystem": "no", "RefuseManualStart": "no", "RefuseManualStop": "no", "RemainAfterExit": "no", "Requires": "-.mount system.slice basic.target", "RequiresMountsFor": "/var/tmp", "Restart": "no", "RestartUSec": "100ms", "Result": "success", "RootDirectoryStartOnly": "no", "RuntimeDirectoryMode": "0755", "SameProcessGroup": "no", "SecureBits": "0", "SendSIGHUP": "no", "SendSIGKILL": "yes", "Slice": "system.slice", "StandardError": "inherit", "StandardInput": "null", "StandardOutput": "journal", "StartLimitAction": "none", "StartLimitBurst": "5", "StartLimitInterval": "10000000", "StartupBlockIOWeight": "18446744073709551615", "StartupCPUShares": "18446744073709551615", "StatusErrno": "0", "StopWhenUnneeded": "no", "SubState": "dead", "SyslogLevelPrefix": "yes", "SyslogPriority": "30", "SystemCallErrorNumber": "0", "TTYReset": "no", "TTYVHangup": "no", "TTYVTDisallocate": "no", "TasksAccounting": "no", "TasksCurrent": "18446744073709551615", "TasksMax": "18446744073709551615", "TimeoutStartUSec": "1min 30s", "TimeoutStopUSec": "1min 30s", "TimerSlackNSec": "50000", "Transient": "no", "Type": "notify", "UMask": "0022", "UnitFilePreset": "disabled", "UnitFileState": "disabled", "WatchdogTimestampMonotonic": "0", "WatchdogUSec": "0"}}
PLAY RECAP *********************************************************************
default : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Ansible server provisioning has other options, such as using Galaxy roles, Host and Group variables, and more. In addition, it can configure and orchestrate not just systems but also networking equipment, web interfaces, and cloud platforms.