{"id":5657,"date":"2020-02-13T00:35:08","date_gmt":"2020-02-13T05:35:08","guid":{"rendered":"\/db-blog\/?p=5657"},"modified":"2020-03-12T01:39:43","modified_gmt":"2020-03-12T05:39:43","slug":"aws-terraform-ansible-openshift-provision-a-lightsail-instance-and-perform-further-configurations-on-it-using-infrastructure-as-code","status":"publish","type":"post","link":"https:\/\/droidbasement.com\/db-blog\/aws-terraform-ansible-openshift-provision-a-lightsail-instance-and-perform-further-configurations-on-it-using-infrastructure-as-code\/","title":{"rendered":"AWS\/Terraform\/Ansible\/OpenShift \u2013 Provision a Lightsail instance and further configure it using Infrastructure as Code"},"content":{"rendered":"\n<p>In this article we will Provision a LightSail host with docker\/docker-compose on it using Terraform and install\/initialize OpenShift Origin on it using Ansible.<\/p>\n\n\n\n<p><a rel=\"noreferrer noopener\" aria-label=\"OpenShift (opens in a new tab)\" href=\"https:\/\/www.openshift.com\/\" target=\"_blank\">OpenShift<\/a> is Red Hat&#8217;s containerization platform which utilizes Kubernetes.  <a href=\"https:\/\/www.okd.io\/\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"Origin (opens in a new tab)\">Origin<\/a> (what we will be working with here) is the opensource implementation of it.<\/p>\n\n\n\n<p>We will use &#8216;myweb&#8217; as an example in this article, using the same base path of &#8216;dev&#8217; that was <a rel=\"noreferrer noopener\" aria-label=\"previously created (opens in a new tab)\" href=\"https:\/\/droidbasement.com\/db-blog\/?p=5346\" target=\"_blank\">previously created<\/a>, the <a rel=\"noreferrer noopener\" aria-label=\"container-admin group (opens in a new tab)\" href=\"https:\/\/droidbasement.com\/db-blog\/?p=5501\" target=\"_blank\">container-admin group<\/a> and using ~\/.local\/bin for the binaries.<\/p>\n\n\n\n<p>Please ensure you have gone through the previous <a rel=\"noreferrer noopener\" aria-label=\"Terraform (opens in a new tab)\" href=\"https:\/\/droidbasement.com\/db-blog\/aws-terraform-provision-a-lightsail-instance-using-infrastructure-as-code\/\" target=\"_blank\">Terraform<\/a>, <a rel=\"noreferrer noopener\" aria-label=\"Ansible (opens in a new tab)\" href=\"https:\/\/droidbasement.com\/db-blog\/aws-ansible-provision-a-lightsail-instance-using-infrastructure-as-code\/\" target=\"_blank\">Ansible<\/a>, related preceding articles and  <a href=\"https:\/\/portal.aws.amazon.com\/billing\/signup?client=lightsail&amp;fid=1A3F6B376ECAC516-2C15C39C5ACECACB&amp;redirect_url=https%3A%2F%2Flightsail.aws.amazon.com%2Fls%2Fsignup#\/start\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"'Get started with Lightsail for free' (opens in a new tab)\">&#8216;Get started with Lightsail for free&#8217;<\/a>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>\u2013&gt;<br>Edit the IAM Policy &#8220;AllowLightsail&#8221;:<br>AWS UI Console -&gt; Services -&gt; Security, Identity, &amp; Compliance -&gt; IAM -&gt; Policies -&gt; AllowLightsail -&gt; Edit Policy -&gt; JSON -&gt; <\/p>\n\n\n\n<p>Append  lightsail:OpenInstancePublicPorts and  lightsail:CloseInstancePublicPorts after lightsail:ReleaseStaticIp.<\/p>\n\n\n\n<p>It will look like this:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">                  \"lightsail:ReleaseStaticIp\",\n                  \"lightsail:OpenInstancePublicPorts\",\n                  \"lightsail:CloseInstancePublicPorts\"<\/pre>\n\n\n\n<p>Review Policy -&gt; Save Changes<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Go in to the dev directory\/link located within your home directory:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ cd ~\/dev<\/pre>\n\n\n\n<p>Upgrade the AWS CLI on your host:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ pip3 install awscli --upgrade --user &amp;&amp; chmod 754 ~\/.local\/bin\/aws<\/pre>\n\n\n\n<p>Grab the latest version of Terraform:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ wget https:\/\/releases.hashicorp.com\/terraform\/0.12.20\/terraform_0.12.20_linux_amd64.zip<\/pre>\n\n\n\n<p>Unzip it to ~\/.local\/bin and set permissions accordingly on it:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ unzip terraform_0.12.20_linux_amd64.zip -d ~\/.local\/bin &amp;&amp; chmod 754 ~\/.local\/bin\/terraform<\/pre>\n\n\n\n<p>Change to the myweb directory inside terraform:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ cd terraform\/myweb<\/pre>\n\n\n\n<p>Upgrade our code to 12.20 (type yes and enter when prompted):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ terraform 0.12upgrade<\/pre>\n\n\n\n<p>Change our instance from a micro to a medium so it will have sufficient resources to run OpenShift Origin and related:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ sed -i s:micro_2_0:medium_2_0: lightsail.tf<\/pre>\n\n\n\n<p>Output the Public IP of the Provisioned host (along with connection parameters and variables) in to a file which we will feed in to an Ansible playbook run:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ cat &lt;&lt; 'EOF' &gt;&gt; output.tf\n&gt;\n&gt; resource \"local_file\" \"hosts\" {\n&gt;   content              = \"[vps]\\n${aws_lightsail_static_ip.myweb.ip_address} ansible_connection=ssh ansible_user=ubuntu ansible_ssh_private_key_file=~\/.ssh\/myweb instance=${aws_lightsail_instance.myweb.name}\"\n&gt;   filename             = \"${path.module}\/..\/..\/ansible\/hosts\"\n&gt;   directory_permission = 0754\n&gt;   file_permission      = 0664\n&gt; }\n&gt; EOF <\/pre>\n\n\n\n<p>Amend an item from the user_data script:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ sed -i 's:sudo apt-key add -:apt-key add -:' scripts\/install.sh<\/pre>\n\n\n\n<p>Initialize the directory\/refresh module(s):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ terraform init<\/pre>\n\n\n<p>Run a dry-run to see what will occur:<\/p>\n\n\n<pre class=\"wp-block-preformatted\">$ terraform plan<\/pre>\n\n\n\n<p>Provision:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ terraform apply -auto-approve<\/pre>\n\n\n\n<p>Create a work folder for an Ansible playbook:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ cd ..\/..\/ansible\n$ mkdir -p openshift\/scripts &amp;&amp; cd openshift<\/pre>\n\n\n\n<p>Create an Ansible playbook which will install\/initialize OpenShift Origin on our provisioned host:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ cat &lt;&lt; 'EOF' &gt; openshift.yml \n&gt; # Install, initialize OpenShift Origin and create a destroy routine for it\n&gt; ---\n&gt; - hosts: vps\n&gt;   connection: local\n&gt;\n&gt;   vars:\n&gt;     openshift_directory: \/home\/ubuntu\/.local\/etc\/openshift\n&gt;\n&gt;   tasks:\n&gt;     - name: Discover Services\n&gt;       service_facts:\n&gt;\n&gt;     - name: Check if openshift directory exists\n&gt;       stat:\n&gt;         path: \"{{ openshift_directory }}\"\n&gt;       register: openshift_dir\n&gt;\n&gt;     - name: Open Firewall Ports\n&gt;       delegate_to: localhost\n&gt;       command: bash -c '.\/scripts\/firewall.sh open {{ hostvars[groups['vps'][0]].instance }}'\n&gt;       when:\n&gt;         - \"'docker' in services\"\n&gt;         - openshift_dir.stat.exists == False\n&gt;  \n&gt;     - name: Copy and Run install\n&gt;       environment:\n&gt;         PATH: \"{{ ansible_env.PATH}}:{{ openshift_directory }}\/..\/..\/bin\"\n&gt;       args:\n&gt;         executable: \/bin\/bash\n&gt;       script: \".\/scripts\/install.sh {{ ansible_ssh_host }}\"\n&gt;       when:\n&gt;         - \"'docker' in services\"\n&gt;         - openshift_dir.stat.exists == False\n&gt;\n&gt;     - debug: msg=\"Please install docker to proceed.\"\n&gt;       when: \"'docker' not in services\"\n&gt;\n&gt;     - debug: msg=\"Install script has already been completed.  Run this playbook with the destroy tag, then run once again normally to re-intialize openshift.\"\n&gt;       when: openshift_dir.stat.exists == True\n&gt;\n&gt;     - name: Destroy\n&gt;       become: yes\n&gt;       environment:\n&gt;         PATH: \"{{ ansible_env.PATH}}:{{ openshift_directory }}\/..\/..\/bin\"\n&gt;       args:\n&gt;         executable: \/bin\/bash\n&gt;       shell: \"cd {{ openshift_directory }} &amp;&amp; oc cluster down &amp;&amp; cd ..\/ &amp;&amp; rm -r {{ openshift_directory }}\/..\/..\/..\/.kube {{ openshift_directory }}\"\n&gt;       tags: [ 'never', 'destroy' ]\n&gt;\n&gt;     - name: Close Firewall Ports\n&gt;       delegate_to: localhost\n&gt;       command: bash -c '.\/scripts\/firewall.sh close {{ hostvars[groups['vps'][0]].instance }}'\n&gt;       tags: [ 'never', 'destroy' ]\n&gt; EOF    <\/pre>\n\n\n\n<p>Create a shell script which will pull the latest release of client tools from GitHub, place the needed binaries in ~\/.local\/bin, set insecure registry on Docker and initialize:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ cat &lt;&lt; 'EOF' &gt; scripts\/install.sh\n&gt; #!\/bin\/bash\n&gt; [[ -z $* ]] &amp;&amp; { echo \"Please specify a Public IP or Host\/Domain name.\" &amp;&amp; exit 1; }\n&gt; # Fetch and Install\n&gt; file_url=\"$(curl -sL https:\/\/github.com\/openshift\/origin\/releases\/latest | grep \"download.*client.*linux-64\" | cut -f2 -d\\\" | sed 's\/^\/https:\\\/\\\/github.com\/')\"\n&gt; [[ -z $file_url ]] &amp;&amp; { echo \"The URL could not be obtained.  Please try again shortly.\" &amp;&amp; exit 1; }\n&gt; file_name=\"$(echo $file_url | cut -f9 -d\/)\"\n&gt; if [[ ! -f $file_name ]]; then\n&gt;         curl -sL $file_url --output $file_name\n&gt;         folder_name=\"$(tar ztf $file_name 2&gt;\/dev\/null | head -1 | sed s:\/.*::)\"\n&gt;         [[ -z $folder_name ]] &amp;&amp; { echo \"The archive could not be read.  Please try again.\" &amp;&amp; rm -f $file_name &amp;&amp; exit 1; }\n&gt;         tar zxf $file_name\n&gt;         mv $folder_name\/oc $folder_name\/kubectl $HOME\/.local\/bin &amp;&amp; rm -r $folder_name\n&gt;         chmod 754 $HOME\/.local\/bin\/oc $HOME\/.local\/bin\/kubectl\n&gt; fi\n&gt; # Docker insecure\n&gt; [[ $(grep insecure \/etc\/docker\/daemon.json &amp;&gt;\/dev\/null; echo $?) -eq 2 ]] &amp;&amp; redirect=\"&gt;\"\n&gt; [[ $(grep insecure \/etc\/docker\/daemon.json &amp;&gt;\/dev\/null; echo $?) -eq 1 ]] &amp;&amp; redirect=\"&gt;&gt;\"\n&gt; [[ $(grep insecure \/etc\/docker\/daemon.json &amp;&gt;\/dev\/null; echo $?) -eq 0 ]] || { sudo bash -c \"cat &lt;&lt; 'EOF' $redirect \/etc\/docker\/daemon.json\n&gt; {\n&gt;         \\\"insecure-registries\\\" : [ \\\"172.30.0.0\/16\\\" ]\n&gt; }\n&gt; EOF\" &amp;&amp; sudo systemctl restart docker; }\n&gt; # OpenShift Origin up\n&gt; [[ ! -d $HOME\/.local\/etc\/openshift ]] &amp;&amp; { mkdir -p $HOME\/.local\/etc\/openshift &amp;&amp; cd $HOME\/.local\/etc\/openshift; } || { cd $HOME\/.local\/etc\/openshift &amp;&amp; oc cluster down; }\n&gt; oc cluster up --public-hostname=$1\n&gt;\n&gt; exit 0\n&gt; EOF <\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>The Lightsail firewall functionality is currently being implemented in Terraform and is not available in Ansible.  In the interim, we will create a shell script to open and close ports needed by OpenShift Origin (using the AWS CLI).  This script will be run locally via the Playbook during the create and destroy routines:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ cat &lt;&lt; 'EOF' &gt; scripts\/firewall.sh &amp;&amp; chmod 754 scripts\/firewall.sh\n&gt; #!\/bin\/bash\n&gt; #\n&gt; openshift_ports=\"53\/UDP 443\/TCP 1936\/TCP 4001\/TCP 7001\/TCP 8053\/UDP 8443\/TCP 10250_10259\/TCP\"\n&gt; #\n&gt; [[ -z $* || $(echo $* | xargs -n1 | wc -l) -ne 2 || ! ($* =~ $(echo '\\&lt;open\\&gt;') || $* =~ $(echo '\\&lt;close\\&gt;')) ]] &amp;&amp; { echo \"Please pass in the desired action [ open, close ] and instance [ site_myweb ].\" &amp;&amp; exit 2; }\n&gt; #\n&gt; instance=\"$(echo $* | xargs -n1 | sed '\/\\&lt;open\\&gt;\/d; \/\\&lt;close\\&gt;\/d')\"\n&gt; [[ -z $instance ]] &amp;&amp; { echo \"Please double-check the passed in instance.\" &amp;&amp; exit 1; }\n&gt; action=\"$(echo $* | xargs -n1 | grep -v $instance)\"\n&gt; #\n&gt; for port in $openshift_ports; do\n&gt;         aws lightsail $action-instance-public-ports --instance $instance --port-info fromPort=$(echo $port | cut -f1 -d_ | cut -f1  -d\/),protocol=$(echo $port | cut -f2 -d\/),toPort=$(echo $port | cut -f2 -d_ | cut -f1 -d\/)\n&gt; done\n&gt; #\n&gt;\n&gt; exit 0\n&gt; EOF <\/pre>\n\n\n\n<p>Run the Ansible playbook after a few minutes (accept the host key by typing yes and hitting enter when prompted):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ ansible-playbook -i ..\/hosts openshift.yml<\/pre>\n\n\n\n<p>After a short while, log on to the instance:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ ssh -i ~\/.ssh\/myweb ubuntu@&lt;The value of static_public_ip that was reported.  One can also use 'terraform output static_public_ip' to print it again.&gt;<\/pre>\n\n\n\n<p>To get an overview of the current project with any identified issues:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ oc status --suggest<\/pre>\n\n\n\n<p>Log on as Admin via CMD Line and switch to the default project:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ oc login -u system:admin -n default<\/pre>\n\n\n\n<p>Logout of the session:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ oc logout<\/pre>\n\n\n\n<p>Please see the <a rel=\"noreferrer noopener\" aria-label=\"Command-Line Walkthrough (opens in a new tab)\" href=\"https:\/\/docs.openshift.com\/enterprise\/3.2\/getting_started\/developers_cli.html\" target=\"_blank\">Command-Line Walkthrough<\/a>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Logout from the host:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ logout<\/pre>\n\n\n\n<p>Log on as Admin via Web Browser (replace &lt;PUBLIC_IP&gt;):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">https:\/\/&lt;PUBLIC_IP&gt;:8443\/console (You will get a Certificate\/Site warning due to a mismatch).<\/pre>\n\n\n\n<p>Please see the <a href=\"https:\/\/docs.openshift.com\/enterprise\/3.2\/getting_started\/developers_console.html\" target=\"_blank\" rel=\"noreferrer noopener\" aria-label=\"Web Console Walkthrough (opens in a new tab)\">Web Console Walkthrough<\/a>.<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>To shut down the OpenShift Origin cluster, destroy the working folder and start anew (you can re-run the playbook normally to reinitialize):<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ ansible-playbook -i ..\/hosts openshift.yml --tags \"destroy\"<\/pre>\n\n\n\n<p><\/p>\n\n\n\n<p>Tear down what was created by first performing a dry-run to see what will occur:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ cd ..\/..\/terraform\/myweb &amp;&amp; terraform plan -destroy <\/pre>\n\n\n\n<p>Tear down the instance:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$ terraform destroy -auto-approve<\/pre>\n\n\n\n<p>&lt;&#8211;<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>References:<br><a rel=\"noreferrer noopener\" href=\"https:\/\/www.techrepublic.com\/article\/how-to-install-openshift-origin-on-ubuntu-18-04\" target=\"_blank\">how-to-install-openshift-origin-on-ubuntu-18-04<\/a> <\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>Source: <br><a rel=\"noreferrer noopener\" href=\"https:\/\/github.com\/pershoot\/ansible_openshift\" target=\"_blank\">ansible_openshift<\/a> <\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this article we will Provision a LightSail host with docker\/docker-compose on it using Terraform and install\/initialize OpenShift Origin on it using Ansible. OpenShift is Red Hat&#8217;s containerization platform which utilizes Kubernetes. Origin (what we will be working with here) is the opensource implementation of it. We will use &#8216;myweb&#8217; as an example in this [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5],"tags":[],"class_list":["post-5657","post","type-post","status-publish","format-standard","hentry","category-devops"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/posts\/5657","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/comments?post=5657"}],"version-history":[{"count":109,"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/posts\/5657\/revisions"}],"predecessor-version":[{"id":6240,"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/posts\/5657\/revisions\/6240"}],"wp:attachment":[{"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/media?parent=5657"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/categories?post=5657"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/droidbasement.com\/db-blog\/wp-json\/wp\/v2\/tags?post=5657"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}