<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Software Deployment on Digi Hunch</title><link>https://static.digihunch.com/tag/software-deployment/</link><description>Recent content in Software Deployment on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Sat, 20 Jul 2024 21:53:05 -0400</lastBuildDate><atom:link href="https://static.digihunch.com/tag/software-deployment/index.xml" rel="self" type="application/rss+xml"/><item><title>Getting started with GitHub Actions</title><link>https://static.digihunch.com/2021/05/getting-started-with-github-actions/</link><pubDate>Thu, 27 May 2021 13:52:31 -0400</pubDate><guid>https://static.digihunch.com/2021/05/getting-started-with-github-actions/</guid><description>&lt;p class="wp-block-paragraph"&gt;In my &lt;a class="rank-math-link" href="https://github.com/digihunch/orthweb"&gt;orthweb&lt;/a&gt; &lt;a href="https://static.digihunch.com/projects/"&gt;project&lt;/a&gt;, I had to compile a library on my own. In search for free computing resources I realized that GitHub action can meet all my needs.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-ci-cd-pipeline"&gt;CI/CD pipeline&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As a development project grows, there are many operational tasks demanding automation. Prior to pipeline technology, developers used to use &lt;a href="https://en.wikipedia.org/wiki/Make_(software)"&gt;Makefile&lt;/a&gt; to organize command execution locally. Today, its role has declined, but &lt;a href="https://tech.trivago.com/post/2019-12-20-makefiles-in-2019/"&gt;Makefile&lt;/a&gt; is a good choice in certain situations. In most cases though, to offload the build command execution to a shared system, automation engines like Jenkins came around. Then Jenkins evolved into pipelines.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In strict terms, CI pipeline is the build pipeline; and CD pipeline is release pipeline. The two types of pipelines use pretty much the same pool of building blocks, with different purposes. The build pipeline focuses on producing quality artifact in a consistent manner. The release pipelines focus on system stability while deploying an artifact across different environments. Because release pipelines may connect to different environment, it has to deal with various situations. It is very common to have multiple stages in release pipeline, each stage pointing to a different environment (e.g. DEV, TEST and PROD). At workplace both could be loosely referred to as CI/CD pipeline, or even simply pipeline.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A lot of projects provide pipeline capability: BitBucket, Bamboo, TeamCity, Jenkins, Azure DevOps, AWS CodePipeline, TravisCI etc. Since late 2018, GitHub also joined the game with GitHub actions. It is openly &lt;a class="rank-math-link" href="https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions#:~:text=GitHub%20Actions%20usage%20is%20free,is%20controlled%20by%20spending%20limits."&gt;free&lt;/a&gt; for public repositories, and has a free tier for private repositories. It executes task as defined in .github/workflow/action.yaml in the code project. I will take my own project as an example.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-runners"&gt;Runners&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You can run jobs in self-hosted runners or GitHub managed runners, similar to other pipeline solutions (e.g. self-hosted agent vs managed agent from Azure DevOps). The &lt;a href="https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#github-hosted-runners" class="rank-math-link"&gt;GitHub hosted runners&lt;/a&gt; only have three operating systems to support: Windows, Ubuntu and MacOS. The Ubuntu and Windows runners are built from Standard_DS2_v2 VMs in Microsoft Azure. They are pre-installed with a &lt;a href="https://github.com/actions/virtual-environments" class="rank-math-link"&gt;virtual environment &lt;/a&gt;with packages required for common build tasks. The same virtual environment is also used in hosted agents by Azure DevOps. While they are free and you can elevate privilege on the runner, you cannot SSH or RDP to it for further troubleshooting. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The &lt;a href="https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners" class="rank-math-link"&gt;self-hosted runners&lt;/a&gt; require users to manage the instance on their own, including configuring virtual environment, installing &lt;a href="https://github.com/actions/runner" class="rank-math-link"&gt;GitHub Action Runner&lt;/a&gt;, etc.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-workflow-file"&gt;Workflow file&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Most pipeline declaration uses YAML or JSON, such as &lt;a href="https://www.jenkins.io/doc/book/pipeline/jenkinsfile/" class="rank-math-link"&gt;Jenkinsfile&lt;/a&gt;, AWS &lt;a href="https://docs.aws.amazon.com/code-samples/latest/catalog/code-catalog-cloudformation-codepipeline.html" class="rank-math-link"&gt;CodePipeline&lt;/a&gt;. GitHub refers to an automation process as a &amp;#8220;workflow&amp;#8221; and you can program the workflow in YAML (.github/workflow/action.yaml). Here is the &lt;a href="https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions" class="rank-math-link"&gt;reference&lt;/a&gt; and an example with environmental variable and versioning: &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;script src="https://gist.github.com/digihunch/e6ed668872c5b0506d25f638ff70727e.js"&gt;&lt;/script&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The handling of environment is documented &lt;a href="https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable" class="rank-math-link"&gt;here&lt;/a&gt;. There are a lot of custom actions available in GitHub &lt;a href="https://github.com/marketplace" class="rank-math-link"&gt;Marketplace&lt;/a&gt;. For example, the versioning in the above example, uses an &lt;a href="https://github.com/marketplace/actions/nuget-build-number-generator" class="rank-math-link"&gt;action&lt;/a&gt; by &lt;a href="https://einaregilsson.com/a-github-action-for-generating-sequential-build-numbers/" class="rank-math-link"&gt;Einar Egilsson&lt;/a&gt;, which is open source itself.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-example-pipeline"&gt;Example pipeline&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;My example &lt;a href="https://github.com/digihunch/orthweb/blob/67542d9329be36e3b8ca895c8b71805c9711aaa3/.github/workflows/action.yml" class="rank-math-link"&gt;pipeline&lt;/a&gt; consists of two phases: &lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Build Library: spin up a docker container to build source code, and publish the artifact&lt;/li&gt;&#10;&lt;li&gt;Publish Image: add the artifact to an existing Docker image, and publish the result as my own image.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The status of the pipeline is also open, and can be found &lt;a href="https://github.com/digihunch/orthweb/actions" class="rank-math-link"&gt;here&lt;/a&gt;. The retention period of artifact is 90 days by default but can be &lt;a href="https://docs.github.com/en/actions/reference/usage-limits-billing-and-administration#artifact-and-log-retention-policy" class="rank-math-link"&gt;customized&lt;/a&gt;. To persist the artifact, I add it to my own Docker image and publish it to &lt;a href="https://hub.docker.com/r/digihunch/orthanc-plugin" class="rank-math-link"&gt;DockerHub&lt;/a&gt;, hence the second phase.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1152" height="724" src="https://static.digihunch.com/wp-content/uploads/2021/05/image-1.png" alt="" class="wp-image-2299"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt; When building the second phase, I need to generate secret from my DockerHub account and store that &lt;a href="https://docs.github.com/en/actions/reference/encrypted-secrets" class="rank-math-link"&gt;encrypted secrets&lt;/a&gt; in GitHub settings, so that the secret value can be referenced in workflow file.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Failures in Actions are displayed in error steps and by default the rest of the steps are skipped. &lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="968" height="624" src="https://static.digihunch.com/wp-content/uploads/2021/05/image-2.png" alt="" class="wp-image-2301"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I use the &lt;strong&gt;&lt;a class="rank-math-link" href="https://github.com/marketplace/actions/docker-build-push-action"&gt;Docker build &amp;amp; push plugin&lt;/a&gt;&lt;/strong&gt; to build and push my own docker image to DockerHub. Apart from DockerHub as my choice, GitHub also has its own artifactory GitHub &lt;a class="rank-math-link" href="https://github.com/features/packages"&gt;Packages&lt;/a&gt; with a small free tier. It supports NPM, Docker, Maven, Gradle, etc. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Triggers of Action&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Most of the times, GitHub action are triggered upon commit to main branch of the repo. In GitHub, this is known as a &lt;a href="https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#workflow_dispatch"&gt;workflow_dispatch&lt;/a&gt; event. This is not the only event that can trigger GitHub action. All the available events are listed &lt;a href="https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#available-events"&gt;here&lt;/a&gt; on its documentation. This makes it very flexible to trigger action at many points in the workflow. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;One example is to trigger GitHub action during PR review. When a developer opens a PR with a few commits in the proposed branch, the PR can preemptively check linting, style, etc and even build the application. These activities can also be defined in a GitHub action manifest with &lt;strong&gt;pull_request&lt;/strong&gt; as triggering event.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Troubleshooting&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In general, it is painful to troubleshoot activities happening inside of runners. I often had to write a few steps for the sake of printing variables, and trigger a run to see what their value is. This requires a lot of time especially when I have to wait for available runners. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To help troubleshooting pipeline runs there is an open-source utility called &lt;a href="https://github.com/nektos/act"&gt;act&lt;/a&gt;. You can run GitHub actions locally from a Docker container on your MacBook. You can deliver environment variables and secrets via files. If you ever need to troubleshoot the runner environment, you have the option to connect to the Shell environment inside of the runner container. This tool is extremely helpful.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-closing-remarks"&gt;Closing remarks&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;GitHub action really makes the CI/CD pipeline capability available to any developers who stores their code on GitHub. GitHub expands from a code repository solution to a full CI/CD solution with a free tier sufficient for personal projects.&lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2021/05/secure-web-application-deployment/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Secure web application deployment&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2021/06/kubernetes-storage-explained/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Kubernetes Storage Explained – from in-tree plugin to CSI&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>AWS CDK example in Typescript – provision an AWX server</title><link>https://static.digihunch.com/2020/12/ansible-tower-lab-environment-on-aws/</link><pubDate>Sat, 19 Dec 2020 17:14:00 -0400</pubDate><guid>https://static.digihunch.com/2020/12/ansible-tower-lab-environment-on-aws/</guid><description>&lt;p class="wp-block-paragraph"&gt;This post provides an example of using AWS CDK in Typescript.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-ansible-tower-and-awx"&gt;Ansible Tower and AWX&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We have used open-source &lt;a href="https://static.digihunch.com/2020/05/revamp-ansible-directory-for-scalability-1-of-2/" class="rank-math-link"&gt;Ansible&lt;/a&gt; extensively in the past. While the automation is convenient, the lack of UI makes it not as suitable as a team collaboration tool. One way to allow team collaboration with open-source Ansible, is to use Jenkins to glue the components together, as discussed in the &lt;a href="https://static.digihunch.com/2020/09/automated-deployment-pipeline-1-2/" class="rank-math-link"&gt;Automated Deployment Pipeline&lt;/a&gt; series. In this setup, the open-source Ansible remains command-line driven, with Jenkins building up the command, rather than a human user. There are many upsides in this configuration, but it is not built specifically for Ansible. Ansible is agent-less, and can be run from any host. This sounds appealing and can work well in smaller server fleet. However, since it requires some configuration on the controlling host for Ansible to function properly, it become unnecessary to configure Ansible environment on every single host (e.g. production). A typically environment only has Ansible environment configured on the bastion host. This brings the need for a dedicated controller server to drive all Ansible tasks.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://www.ansible.com/products/tower" class="rank-math-link"&gt;Ansible Tower&lt;/a&gt; is Red Hat&amp;#8217;s commercial enhancement to the open source Ansible, providing web-based console, REST API and other services such as Role-based Access Control (RBAC). Managing Ansible via REST API is still somewhat involving but this also enables other open-source contributions to simplify the use of API. For example &lt;a href="https://docs.ansible.com/ansible-tower/3.5.3/html/towerapi/tower_cli.html" class="rank-math-link"&gt;Tower CLI&lt;/a&gt; allows you to use Ansible Tower with simplified command. Ansible Tower has an open-source upstream project called &lt;a href="https://www.ansible.com/products/awx-project/faq" class="rank-math-link"&gt;AWX&lt;/a&gt;, maintained by Red Hat. &lt;a href="https://github.com/ansible/awx" class="rank-math-link"&gt;AWX&lt;/a&gt; is essentially a preview release of Ansible Tower without commercial support. AWX can serve as an engine for all Ansible related task. AWX server is essentially an Ansible control server. AWX, or Ansible Tower, also brings several concepts on top of Ansible:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;Job template:&lt;/strong&gt; defines how an Ansible playbook should be executed, including details such as machine credential, project, inventory, and playbook file.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Job:&lt;/strong&gt; the actual execution of job template&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Project: &lt;/strong&gt;connects Ansible Tower to source control such as BitBucket. It is tied to a Git repository and a branch within that repository&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To deploy AWX on EC2 instances, there is a &lt;a href="https://aws.amazon.com/quickstart/architecture/awx/" class="rank-math-link"&gt;reference deployment&lt;/a&gt; by AWS. However, it is provided as CloudFormation template and appears to be outdated (from 2018). In our &lt;a href="https://github.com/digihunch/atlab" class="rank-math-link"&gt;project&lt;/a&gt; (late 2020, named ansible tower lab, or dubbed as &amp;#8220;atlab&amp;#8221;), we provide the infrastructure in AWS CDK (written in typescript), to provision the AWX environment. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The goal is that once the configuration is completed, you can run ansible ping against a target EC2 instance. The steps are as automated as possible. However, a number of key steps are purposefully left manual for learning purpose, such as the installation of AWX on EC2 instance.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-infrastructure-as-code"&gt;Infrastructure as Code&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In previous &lt;a href="https://static.digihunch.com/2020/12/instance-initialization-with-aws-cdk-in-python/"&gt;posting&lt;/a&gt;, I created infrastructure as code in AWS CDK with Python, so I decided to change to typescript in this project, with the assumption it is just a matter of syntax mapping. However, I underestimated the transition to a new language I never learned before. A fuzzy understanding of little details such as when to use let a=4 vs this.a=4, may produce elusive errors that takes hours to troubleshoot. I would therefore strongly recommend reading the basic syntax &lt;a class="rank-math-link" href="https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes-oop.html"&gt;guide&lt;/a&gt; for typescript, before getting started. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In typescript, this example project provides an implementation of configuring autoscaling groups, including cloud init, user data, etc on AWS. Other than the language, everything else is very similar to the project in this &lt;a href="https://static.digihunch.com/2020/12/instance-initialization-with-aws-cdk-in-python/" class="rank-math-link"&gt;post&lt;/a&gt;, which was developed in Python. Also, note that the project directory structure varies slightly based on the language being used.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If you are absolutely new to AWS cdk, start with this &lt;a href="https://docs.aws.amazon.com/cdk/latest/guide/hello_world.html" class="rank-math-link"&gt;app&lt;/a&gt;. It is beyond the scope of this post, to cover extensively the installation and environment configuration of AWS CDK.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the provision process for Bastion host, the cloudformation init script pulls a specific version from AWX repository, then makes slight modification. User will need to install it manually. Note that AWX can be installed on three types of platforms:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;OpenShift&lt;/li&gt;&#10;&lt;li&gt;Kubernetes&lt;/li&gt;&#10;&lt;li&gt;Docker Compose&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;All are documented in their &lt;a class="rank-math-link" href="https://github.com/ansible/awx/blob/devel/INSTALL.md"&gt;README file&lt;/a&gt;. For simplicity in this project, the installation is on standalone docker compose. This is the default mode so there is no need to modify the inventory file.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-the-code-repo"&gt;The code repo&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The repository is version controlled &lt;a href="https://github.com/digihunch/atlab" class="rank-math-link"&gt;here&lt;/a&gt;. To run the project, you need to have aws cli environment, then install the required packages including node js, and npm packages such as aws cdk. Once configured, validate with command:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cdk ls&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This should display the stacks available. Use cdk deploy to deploy each stack.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When BastionStack is deployed, dependent packages should be installed with user data and cloud init. You will just need to SSH on to the server to manually install AWX, as explained in the instruction, to manually install AWX:&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ansible-playbook -i inventory install.yml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then you can browse to the server (at port 80 by default). Before the log-in page for the first time, the AWX will upgrade itself, with the following screen presented:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1446" height="988" src="https://static.digihunch.com/wp-content/uploads/2020/12/image-1.png" alt="" class="wp-image-1968"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Now log on with default credential (in README.md), you will have the UI for AWX:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1297" height="930" src="https://static.digihunch.com/wp-content/uploads/2020/12/image-4.png" alt="" class="wp-image-1979"/&gt;&lt;figcaption class="wp-element-caption"&gt;AWX Web Console&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;From here, you can edit inventory by adding the host. Or use the helper script (~/awxcompose-helper.sh) from bastion host to create a new inventory (named Private Instance Inventory), and populate it with the hosts in the stack. The helper script does so by querying aws resource, and isssue rest API calls to AWX. After executing the script, you can see a new inventory, and the Private instance inventory should contain all hosts in the stack:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="756" height="774" src="https://static.digihunch.com/wp-content/uploads/2020/12/image-6.png" alt="" class="wp-image-1986"/&gt;&lt;figcaption class="wp-element-caption"&gt;Automatically populated inventory&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You can then run Ansible ping against the host to validate connectivity. Note that during inventory creation, the ansible_user is already set to ec2-user (by the helper script):&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="921" height="908" src="https://static.digihunch.com/wp-content/uploads/2020/12/image-7.png" alt="" class="wp-image-1987"/&gt;&lt;figcaption class="wp-element-caption"&gt;Ping result&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;h3 class="wp-block-heading" id="h-some-technical-details"&gt;Some technical details&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The initialization process on Bastion host creates an RSA key pair, stores the public key to AWS, for the upcoming private instances to uses. It keeps the private key locally in order to make outgoing SSH connection to the private instances. To ensure connectivity between AWX and private instances, there are a couple of (bash) helper scripts involved. Both reflects some technical details that I had to work through.&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;awxcompose-helper.sh&lt;/strong&gt;: the initialization process pulls AWX installation file from git repo. The installation process will build a docker-compose file in ~/.awx/awxcompose, based on a template (~/awx-*/installer/roles/local_docker/templates/docker-compose.yml.j2). When user tells AWX to connect to private instance, the connection was made out of a docker container (instead of from the OS of bastion host), we need this script to map SSH key file from host to container, by modifying the template file. Without this helper, outgoing SSH connection will fail with error (Permission denied (publickey,gssapi-keyex,gssapi-with-mic)). This script is invoked in the cloud init process without requiring manual execution.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;awxinvt-helper.sh&lt;/strong&gt;: once the private stack is up and the installation has completed, we need to add the hosts to AWX inventory. This script gets the instance ID and IP addresses of the private instances, and uses Rest API calls to create inventory and populate it with hosts. Ansible has multiple &lt;a href="https://www.ansible.com/blog/summary-of-authentication-methods-in-red-hat-ansible-tower" class="rank-math-link"&gt;ways of authentication&lt;/a&gt;. This script uses the non-stateful basic authentication with each curl command requiring credential. Ansible Rest API guide is provided &lt;a href="https://docs.ansible.com/ansible-tower/latest/html/towerapi/api_ref.html" class="rank-math-link"&gt;here&lt;/a&gt; and be wary of the &lt;a href="https://docs.ansible.com/ansible-tower/latest/html/towerapi/conventions.html" class="rank-math-link"&gt;convention&lt;/a&gt; where URI must end with a slash. &lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This project is just a start of AWX on AWS CDK project using Typescript. In real life scenarios, there are some work to do to make this even more automated. For example, use cfn-hup service to monitor changes of private stack, and therefore update inventories accordingly. &lt;/p&gt;&#10;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2020/12/high-performance-computing-cluster/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;High Performance Computing&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2021/01/basic-kubernetes-resource-object-1-of-2/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Basic Resource Object in Kubernetes 1 of 2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>