<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>centos on Digi Hunch</title><link>https://static.digihunch.com/tag/centos/</link><description>Recent content in centos on Digi Hunch</description><generator>Hugo -- gohugo.io</generator><language>en-US</language><lastBuildDate>Tue, 08 Apr 2025 14:41:31 -0400</lastBuildDate><atom:link href="https://static.digihunch.com/tag/centos/index.xml" rel="self" type="application/rss+xml"/><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><item><title>Docker storage</title><link>https://static.digihunch.com/2020/11/docker-storage/</link><pubDate>Tue, 03 Nov 2020 20:22:00 -0400</pubDate><guid>https://static.digihunch.com/2020/11/docker-storage/</guid><description>&lt;p class="wp-block-paragraph"&gt;Microservices are all about stateless and ephemeral workloads, and containers are great microservices. This may suggest that that Docker is all about ephemeral storage. In fact, Docker supports both non-persistent and persistent storage, such as database, kafka, etc. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Non-persistent storage is automatically created, alongside the container and is tied to the lifecycle of the container. On Linux system, it is /var/lib/docker/ as part of container. This is referred to as local storage.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Docker has a concept of volume, which is essentially a file or a directory. Volumes are for persistent data. they are de-coupled from containers and are not tied to the lifecycle of any container. Volume allows process in docker container to bypass the default uionFS, and stores file or directory on host machine. It also allows different containers to share data. You may mount a volume to a container. even if container is deleted, volume persists.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;By default, Docker creates new volumes with the built-in local driver. Local volumes are only available to containers on the node they&amp;#8217;re created on. There are also third-party drivers as plugins that provides advanced options to integrate external storage system with Docker. (NAS, SAN, etc)&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are more than 25 volume plugins that you can specify with -d switch, to cover all three categories of storage&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Block storage tends to be high performance and good for small-block random access workloads.&lt;/li&gt;&#10;&lt;li&gt;File storage is high performance, shared amongs multiple containers with NFS or SMB protocols.&lt;/li&gt;&#10;&lt;li&gt;Object storage is good for long term storage of large data blobs that do not change frequently. It is often content addressable and relatively low performance.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Note that if you share volume with multiple containers, the application needs to worry about data collision.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You may use docker volume create command to create volume. Note that there is no quota management within docker so the partition needs to be managed at operating system level.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Implementation of Volume&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Remember that Docker image is built on multi-layer file system. When we run a container, Docker places a read-write layer on top of the image, such that the active files in running container are all placed in this read-write layer. When container is deleted, so are the files. The file system in Docker is a pseudo file system implemented in unionFS. Volumes bypasses the uionFS and directly accesses the host file system. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When we create a Docker volume, Docker places the volume data to /var/lib/docker/volumes and under each directory named after volume, creates a directory _data, which is attached to the corresponding container.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You can even mount an NFS volume to container. Reference &lt;a href="https://forums.docker.com/t/nfs-mount-inside-docker-container-bypassing-the-host/77890" class="rank-math-link"&gt;here&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We mentioned UnionFS a couple times so far. UnionFS is a light-weight, layered file system. It can mount the contents of multiple directories to the same directory, to form a single file system. User can use unionFS like a directory. It is the foundation of Docker image and container and enables saving of spaces.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" width="1024" height="444" src="https://static.digihunch.com/wp-content/uploads/2024/07/unionfs-1024x444.png" alt="" class="wp-image-11424" style="width:526px;height:auto" srcset="https://static.digihunch.com/wp-content/uploads/2024/07/unionfs-1024x444.png 1024w, https://static.digihunch.com/wp-content/uploads/2024/07/unionfs-300x130.png 300w, https://static.digihunch.com/wp-content/uploads/2024/07/unionfs-768x333.png 768w, https://static.digihunch.com/wp-content/uploads/2024/07/unionfs.png 1380w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are three common types of union FS: AUFS, DeviceMapper, and OverlayFS.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;AUFS file system&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AUFS is the earliest driver that Docker uses for file system, most common in Ubuntu and Debian. To check if the system support AUFS, check out the documentation &lt;a href="https://docs.docker.com/storage/storagedriver/aufs-driver/" class="rank-math-link"&gt;here&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AUFS is recommended in Ubuntu or Debian. For CentOS and Redhat, it needs to be installed and make sure the command above returns aufs. To configure AUFS, create file /etc/docker/daemon.json and add:&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-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;storage-driver&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;aufs&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then restart docker service. Run &amp;#8220;docker info&amp;#8221; and examine the Storage Driver section, as documented &lt;a href="https://docs.docker.com/storage/storagedriver/aufs-driver/" class="rank-math-link"&gt;here&lt;/a&gt;. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AUFS layers multiple directories on a single Linux host and presents them as a single directory. These directories are called branches in AUFS terminology, and layers in Docker terminology. The unification process is referred to as a union mount.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-full is-resized"&gt;&lt;img loading="lazy" decoding="async" width="884" height="724" src="https://static.digihunch.com/wp-content/uploads/2024/07/ubuntu-layers.png" alt="" class="wp-image-11425" style="width:538px;height:auto" srcset="https://static.digihunch.com/wp-content/uploads/2024/07/ubuntu-layers.png 884w, https://static.digihunch.com/wp-content/uploads/2024/07/ubuntu-layers-300x246.png 300w, https://static.digihunch.com/wp-content/uploads/2024/07/ubuntu-layers-768x629.png 768w" sizes="auto, (max-width: 884px) 100vw, 884px" /&gt;&lt;figcaption class="wp-element-caption"&gt;Layers of a Ubuntu container&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt; &lt;a href="https://docs.docker.com/storage/storagedriver/aufs-driver/#example-image-and-container-on-disk-constructs" class="rank-math-link"&gt;This section&lt;/a&gt; describes how the layers work and &lt;a href="https://docs.docker.com/storage/storagedriver/aufs-driver/#how-container-reads-and-writes-work-with-aufs" class="rank-math-link"&gt;this section&lt;/a&gt; describes how it reads and writes files (Copy-on-Write (CoW) strategy to maximize storage efficiency and minimize overhead). CoW characterized AUFS.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AUFS has not been adopted in the Linux kernel mainline for lack of maintainability. So for CentOS, the recommended file system driver is devicemapper.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Devicemapper file system&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Devicemapper is a technical framework to map physical block device to virtual block device, introduced since kernel 2.6.9. So it&amp;#8217;s essentially different from AUFS. The Logical Volume Manager (LVM) in Linux is also implemented based on devicemapper.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The three critical components in devicemapper are:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;mapped device: a virtual device that devicemapper provides to client&lt;/li&gt;&#10;&lt;li&gt;target device: the underlying physical device or a section of it.&lt;/li&gt;&#10;&lt;li&gt;map table: keeps track of the offset, range, etc between mapped and target devices.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Devicemapper uses target driver to block, filter, and forward I/O requests (e.g. Raid, encryption, think provisioning, etc). In thin provisioning, storage driver only assigns spaces that are needed. Docker uses snapshot technology in thin provisioning. This &lt;a class="rank-math-link" href="https://docs.docker.com/storage/storagedriver/device-mapper-driver/#how-the-devicemapper-storage-driver-works"&gt;part of the documentation&lt;/a&gt; provides further details as to how device mapper works.&lt;/p&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" width="854" height="1024" src="https://static.digihunch.com/wp-content/uploads/2025/04/ubuntu-busybox-layer-854x1024.webp" alt="" class="wp-image-13114" style="width:539px;height:auto" srcset="https://static.digihunch.com/wp-content/uploads/2025/04/ubuntu-busybox-layer-854x1024.webp 854w, https://static.digihunch.com/wp-content/uploads/2025/04/ubuntu-busybox-layer-250x300.webp 250w, https://static.digihunch.com/wp-content/uploads/2025/04/ubuntu-busybox-layer-768x921.webp 768w, https://static.digihunch.com/wp-content/uploads/2025/04/ubuntu-busybox-layer.webp 1046w" sizes="auto, (max-width: 854px) 100vw, 854px" /&gt;&lt;figcaption class="wp-element-caption"&gt;Ubuntu and busybox image layers&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Devicemapper has to modes:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;loop-lvm: in dev and test environment&lt;/li&gt;&#10;&lt;li&gt;direct-lvm: recommended in production&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Here is the performance &lt;a href="https://docs.docker.com/storage/storagedriver/device-mapper-driver/#device-mapper-and-docker-performance" class="rank-math-link"&gt;best practice&lt;/a&gt;. To configure devicemapper, create /etc/docker/daemon.json file and add:&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;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;storage-driver&amp;#34;:&amp;#34;devicemapper&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;storage-opts&amp;#34;:[&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;dm.directlvm_device=/dev/xdf&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;dm.thinp_percent=95&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;dm.thinp_metapercent=1&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;dm.thinp_autoextend_threshold=80&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;dm.thinp_autoextend_percent=20&amp;#34;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &amp;#34;dm.directlvm_device_force=false&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then restart docker service. Run &amp;#8220;docker info&amp;#8221; and examine the Storage Driver section to ensure direct-lvm mode is on. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Since devicemapper uses block device to store files, it is faster than directly operate on file system. It is adopted as default driver as unionFS for a long time, ensuring stable performance under Red Hat and CentOS.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;OverlayFS file system&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Earlier versions of OverlayFS (known as overlay driver) is not stable. Later version is known as overlay2, which is very stable and recommended in overlay2. It requires:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;Docker version higher than 17.06.02;&lt;/li&gt;&#10;&lt;li&gt;Kernel version higher than 3.10.0-514 for CentOS and RHEL; or higher than 4.0 for other distributions of Linux;&lt;/li&gt;&#10;&lt;li&gt;Using with xfs file system with d_type turned on&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In production environment, it is recommended to moutn /var/lib/docker to separate disk or partition, to prevent the directory getting full from impacting the host OS. The option pquota is recommended for mounting options in /etc/fstab.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To configure storage driver, create file /etc/docker/daemon.json, with the following content:&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-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;storage-driver&amp;#34;&lt;/span&gt;:&lt;span style="color:#e6db74"&gt;&amp;#34;overlay2&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;storage-opts&amp;#34;&lt;/span&gt;:&lt;span style="color:#f92672"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;overlay2.size=20G&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;overlay2.override_kernel_check=true&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then restart docker service. Run &amp;#8220;docker info&amp;#8221; and examine the Storage Driver section to ensure storage driver is overlay2 and d_type is true.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The way overlay2 works is similar to AUFS, involving union mount process, with lowerdir, upperdir and merged. More details are &lt;a href="https://docs.docker.com/storage/storagedriver/overlayfs-driver/#how-the-overlay2-driver-works" class="rank-math-link"&gt;here&lt;/a&gt;, including &lt;a href="https://docs.docker.com/storage/storagedriver/overlayfs-driver/#how-the-overlay-driver-works" class="rank-math-link"&gt;how overlay2 works&lt;/a&gt; with file read and file write (e.g. CopyOnWrite).&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Today, overlay2 driver is officially recommended by Docker for its stability and performance, it should be used if all the conditions are met.&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/10/docker-under-the-hood/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Docker components&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/11/medical-imaging-web-server-deployment-pipeline/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Automatic deployment of Orthanc on AWS&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Host legacy application in Docker 2 of 2</title><link>https://static.digihunch.com/2020/10/host-legacy-application-in-docker-2-of-2/</link><pubDate>Thu, 22 Oct 2020 17:54:00 -0400</pubDate><guid>https://static.digihunch.com/2020/10/host-legacy-application-in-docker-2-of-2/</guid><description>&lt;p class="wp-block-paragraph"&gt;My &lt;a href="https://static.digihunch.com/2020/09/host-legacy-application-with-docker-compose/"&gt;previous notes &lt;/a&gt;include some tricks in hosting legacy application in docker. This is a continuation from that work, after 1.5 months&amp;#8230;&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Use Case&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I decided to use docker to host application for a good reason, and let me start with what this Java-based application does as a single process. When it is up it listens to more than 70 TCP ports for different business services. Here is a simplified list:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Application service&lt;/td&gt;&lt;td&gt;TCP port to bind&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Business service A&lt;/td&gt;&lt;td&gt;8030&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Business service B&lt;/td&gt;&lt;td&gt;8040&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Business service C&lt;/td&gt;&lt;td&gt;8050&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&amp;#8230;&amp;#8230;&lt;/td&gt;&lt;td&gt;&amp;#8230;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;figcaption class="wp-element-caption"&gt;TCP port requirement&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The application also communicates with database and search engine on the same server. Since I am building a training environment where multiple instances of our application needs to run on a single server host. All these instances of application share the same underlying database and search engine services. With multiple instances, additional constraints are introduced. For example:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;Each instance requires more than 120 configuration files. A small number of them defines what ports the process binds to. The rest of configuration files are the same across all instances.&lt;/li&gt;&#10;&lt;li&gt;The OS needs to host 6 processes of the same application all running at the same time;&lt;/li&gt;&#10;&lt;li&gt;The OS does not allow multiple processes to bind to a single TCP port (duh!);&lt;/li&gt;&#10;&lt;li&gt;It is extremely labourious to change the path for application to read configuration files from. This bad configuration also breaks the upgrade process going forward. &lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;From the statements of constraints, I determine that we need a mechanism to bring running application process into an isolated environment. This is exactly the definition of container and a perfect use case for docker. The following table represents an example of how the multiple instances can be orchestrated.&lt;/p&gt;&#10;&lt;table id="tablepress-11" class="tablepress tablepress-id-11 tbody-has-connected-cells"&gt;&#10;&lt;thead&gt;&#10;&lt;tr class="row-1"&gt;&#10;&#9;&lt;th class="column-1"&gt;OS&lt;/th&gt;&lt;th class="column-2"&gt;Container ID&lt;/th&gt;&lt;th class="column-3"&gt;Application Service&lt;/th&gt;&lt;th class="column-4"&gt;container port&lt;/th&gt;&lt;th class="column-5"&gt;published port&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody class="row-striping row-hover"&gt;&#10;&lt;tr class="row-2"&gt;&#10;&#9;&lt;td rowspan="9" class="column-1"&gt;Host&lt;br /&gt;&#10;CentOS&lt;/td&gt;&lt;td rowspan="3" class="column-2"&gt;Container 1&lt;br /&gt;&#10;(Instance #1)&lt;/td&gt;&lt;td class="column-3"&gt;Business Service A&lt;/td&gt;&lt;td class="column-4"&gt;8030&lt;/td&gt;&lt;td class="column-5"&gt;9301&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-3"&gt;&#10;&#9;&lt;td class="column-3"&gt;Business Service B&lt;/td&gt;&lt;td class="column-4"&gt;8040&lt;/td&gt;&lt;td class="column-5"&gt;9401&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-4"&gt;&#10;&#9;&lt;td class="column-3"&gt;Business Service C&lt;/td&gt;&lt;td class="column-4"&gt;8050&lt;/td&gt;&lt;td class="column-5"&gt;9501&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-5"&gt;&#10;&#9;&lt;td rowspan="3" class="column-2"&gt;Container 2&lt;br /&gt;&#10;(Instance #2)&lt;/td&gt;&lt;td class="column-3"&gt;Business Service A&lt;/td&gt;&lt;td class="column-4"&gt;8030&lt;/td&gt;&lt;td class="column-5"&gt;9302&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-6"&gt;&#10;&#9;&lt;td class="column-3"&gt;Business Service B&lt;/td&gt;&lt;td class="column-4"&gt;8040&lt;/td&gt;&lt;td class="column-5"&gt;9402&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-7"&gt;&#10;&#9;&lt;td class="column-3"&gt;Business Service C&lt;/td&gt;&lt;td class="column-4"&gt;8050&lt;/td&gt;&lt;td class="column-5"&gt;9502&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-8"&gt;&#10;&#9;&lt;td rowspan="3" class="column-2"&gt;Container 3&lt;br /&gt;&#10;(Instance #3)&lt;/td&gt;&lt;td class="column-3"&gt;Business Service A&lt;/td&gt;&lt;td class="column-4"&gt;8030&lt;/td&gt;&lt;td class="column-5"&gt;9601&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-9"&gt;&#10;&#9;&lt;td class="column-3"&gt;Business Service B&lt;/td&gt;&lt;td class="column-4"&gt;8040&lt;/td&gt;&lt;td class="column-5"&gt;9602&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-10"&gt;&#10;&#9;&lt;td class="column-3"&gt;Business Service C&lt;/td&gt;&lt;td class="column-4"&gt;8050&lt;/td&gt;&lt;td class="column-5"&gt;9603&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;!-- #tablepress-11 from cache --&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This way of orchestration allows the different instances of applications to share as much configuration files as possible, so that each process thinks that they bind to TCP ports (8030, 8040, 8050, etc), by taking advantage of Docker&amp;#8217;s ability to map ports for publishing.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Below is an example of the docker compose file:&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;version: &amp;#39;3.6&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;services:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dapp1:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: docker.digihunch.com/dapp:${DAPP_VER}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; container_name: dapp1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; entrypoint: [&amp;#34;/opt/docker-entrypoint.sh&amp;#34;,&amp;#34;dapp&amp;#34;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ports:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - 9301:8030 # BUSINESS SERVICE A&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - 9401:8040 # BUSINESS SERVICE B&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - 9501:8050 # BUSINESS SERVICE C&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mac_address: 2c:1f:4e:c5:9e:cf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - INSTANCE_TAG=dapp1 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - MAX_JVM_HEAP=${DAPP_HEAP:-3892M}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - vcnet&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; volumes:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - /opt/dapp/etc:/opt/dapp/etc:ro&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ./instances/dapp1/dapp.lic:/opt/dapp/etc/dapp.lic:ro&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ./instances/dapp1/variables:/opt/dapp/etc/variables:ro&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; deploy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; resources:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; limits:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cpus: &amp;#39;0.5&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; memory: ${DAPP_MEM:-4096M}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reservations:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; memory: ${DAPP_MEM:-4096M}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tty: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dapp2:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: docker.digihunch.com/dapp:${DAPP_VER}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; container_name: dapp2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; entrypoint: [&amp;#34;/opt/docker-entrypoint.sh&amp;#34;,&amp;#34;dapp&amp;#34;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ports:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - 9302:8030 # BUSINESS SERVICE A&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - 9402:8040 # BUSINESS SERVICE B&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - 9502:8050 # BUSINESS SERVICE C&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mac_address: 2c:1f:4e:c5:9e:d0 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - INSTANCE_TAG=dapp2 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - MAX_JVM_HEAP=${DAPP_HEAP:-3892M}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - vcnet&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; volumes:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - /opt/dapp/etc:/opt/dapp/etc:ro&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ./instances/dapp2/dapp.lic:/opt/dapp/etc/dapp.lic:ro&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ./instances/dapp2/variables:/opt/dapp/etc/variables:ro&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; deploy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; resources:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; limits:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cpus: &amp;#39;0.5&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; memory: ${DAPP_MEM:-4096M}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reservations:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; memory: ${DAPP_MEM:-4096M}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tty: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dapp3:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; image: docker.digihunch.com/dapp:${DAPP_VER}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; container_name: dapp3&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; entrypoint: [&amp;#34;/opt/docker-entrypoint.sh&amp;#34;,&amp;#34;dapp&amp;#34;]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ports:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - 9601:8030 # BUSINESS SERVICE A&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - 9602:8040 # BUSINESS SERVICE B&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - 9603:8050 # BUSINESS SERVICE C&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mac_address: 2c:1f:4e:c5:9e:d1 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - INSTANCE_TAG=dapp3 &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - MAX_JVM_HEAP=${DAPP_HEAP:-3892M}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - vcnet&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; volumes:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - /opt/dapp/etc:/opt/dapp/etc:ro&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ./instances/dapp3/dapp.lic:/opt/dapp/etc/dapp.lic:ro&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - ./instances/dapp3/variables:/opt/dapp/etc/variables:ro&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; deploy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; resources:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; limits:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cpus: &amp;#39;0.5&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; memory: ${DAPP_MEM:-4096M}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; reservations:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; memory: ${DAPP_MEM:-4096M}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tty: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;networks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; vcnet:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; driver: bridge&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; driver_opts:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; com.docker.network.enable_ipv6: &amp;#34;false&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In this compose file, the environment variables are stored in .env file in the same directory and if they are not declared, the default is specified (syntax: ${VAR:-default}). &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Helper scripts&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The docker commands are fairly long so I had to organize them into several helper scripts. For example:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;docker-entrypoint.sh: this script is the ENTRYPOINT script for container. It is responsible for:&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Initialization work that cannot be done in Dockerfile, such as setting environment variable&lt;/li&gt;&#10;&lt;li&gt;Launch the application, including pointing log file to stdout&lt;/li&gt;&#10;&lt;li&gt;Adding host entry for host.docker.internal to /etc/hosts, as a workaround to &lt;a href="https://stackoverflow.com/questions/24319662/from-inside-of-a-docker-container-how-do-i-connect-to-the-localhost-of-the-mach"&gt;this&lt;/a&gt; issue with Docker on Linux&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;build_image.sh: this script makes the image build process smoother&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;check if image to build already exist, and ask permission to delete the existing image if so;&lt;/li&gt;&#10;&lt;li&gt;build the image with Dockerfile, and create directory structure for Dockerfile to use during COPY instruction&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;start_dapp_all.sh: this script starts all containers using docker-compose up and also add required iptables rules. We need to edit PREROUTING rules in IP tables to allow traffic between host NIC interface and the docker bridge interface, created each time service is up, as pointed out in &lt;a href="https://static.digihunch.com/2020/09/host-legacy-application-with-docker-compose/"&gt;previous post&lt;/a&gt;.&lt;/li&gt;&#10;&lt;li&gt;stop_dapp_all.sh: this script removes the relevant iptables rules and stop all containers using docker-compose. Note that when deleting routing rules by number, start from the highest rule number and work your way down, since each deletion will cause the rules to be re-numbered.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Permission&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The container uses a non-root user to run application (e.g. with su dhunch -c &amp;#8220;command&amp;#8221; from entry point script to run application as dhunch user), because the legacy application uses the same (non-root) user to perform its actions, and it is generally not advised to use root user. To ensure consistency, we need to create the dhunch user in container (in Dockerfile) so it&amp;#8217;s uid and gid aligns with those of the host. The file and directory on the host to be access by the process in container also needs to allow dhunch user to read and write. Otherwise, entry point script will fail.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the docker-compose file, we mount a file or a directory on the host to the container, and specify 😮 if it is read only mount, under volumes. We can alternatively use bind mount (check &lt;a href="https://medium.com/devops-dudes/docker-volumes-and-bind-mounts-2fb4bd9df09d"&gt;here&lt;/a&gt; for comparison). In either case, we need to keep in mind of the permission &amp;#8211; owner alignment. For example, we have the following mount statement under volumes:&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&amp;#8211; /var/lib/dapp/dcontainer/archive:/var/lib/dapp/dhost/archive&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We also need the entire directory hierarchy accessible to dhunch user. To configure this correctly, we need to create the entire directory hierarchy and set proper owner to it. Here is the comparison between the bad configuration and good configuration:&lt;/p&gt;&#10;&lt;figure class="wp-block-table"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Dockerfile instruction for container&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Permission issue during mount by docker-compose&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Bad config&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;RUN mkdir -p /var/lib/dapp &amp;amp;&amp;amp; chown -R dhunch:dhunch /var/lib/dapp&lt;br&gt;&lt;/td&gt;&lt;td&gt;The directory &amp;#8220;dcontainer&amp;#8221; was not created until mount time and it is created implicitly with root as owner (since there is no user section in docker-compose, so root as default is used). The application running as dhunch user in container will have permission issue going into dcontainer directory after mount.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Good config&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;RUN mkdir -p /var/lib/dapp/dcontainer/archive &amp;amp;&amp;amp; chown -R dhunch:dhunch /var/lib/dapp&lt;/td&gt;&lt;td&gt;The directory &amp;#8220;dcontainer&amp;#8221; was already created with proper permission prior to mount and the main application process running as dhunch user will not have permission issue.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For application process running as dhunch, it also needs to write logs to stdout, so the result can be viewed from outside the container using docker logs command. The docker-entrypoint.sh script makes this happen by:&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;su dhunch -c &amp;#34;ln -sf /dev/stdout $DHUNCH_LOG_DIR/dhunch.log&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;However, this command itself will run into permission issues. To fix, we need to add user dhunch to tty group (e.g. in Dockerfile as it&amp;#8217;s needed on every container):&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;usermod -a -G tty dhunch&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;For application process to write to a shared volume on host (e.g. NFS), we can either allow access through volume mapping, or for performant access, mount the NFS share directly to container with proper driver. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Java application&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For Java applications, only use the needed package (openjdk, openjdk-devel, openjdk-headless) as the Docker image size must be kept as small as possible. The headless package is for non-UI components, the devel package is for development stuff.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;It is also worth-noting that the upper limit of heap size (Xmx) should be set based on the reserved memory of container (specified under docker-compose under resource limit and reservation). If heap is larger than container&amp;#8217;s available memory, OOM will be triggered and the container will be killed. &lt;a href="https://developers.redhat.com/blog/2017/03/14/java-inside-docker/"&gt;This article&lt;/a&gt; has some good explanation on this.&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/10/automated-deployment-pipeline-3-of-3/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Automated Deployment Pipeline 3 of 3&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/10/docker-under-the-hood/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Docker components&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Automated Deployment Pipeline 3 of 3</title><link>https://static.digihunch.com/2020/10/automated-deployment-pipeline-3-of-3/</link><pubDate>Wed, 14 Oct 2020 17:27:00 -0400</pubDate><guid>https://static.digihunch.com/2020/10/automated-deployment-pipeline-3-of-3/</guid><description>&lt;h3 class="wp-block-heading" id="h-background"&gt;Background&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We have previously covered a pipeline example with Jenkins calling Ansible to leverage OpenSSH configuration and Ansible inventory. We also discussed a use case with declarative pipeline.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In this posting, I will provide another advanced example, built on declarative pipeline. The pipeline file will be pulled from Git repository. Also, the script is executed on a remote agent, instead of the Jenkins master server. The reason this example is important, is that:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;Jenkinsfile is now version controlled (pipeline as code);&lt;/li&gt;&#10;&lt;li&gt;Service script (e.g. python) is also version controlled from a central repository;&lt;/li&gt;&#10;&lt;li&gt;Computing resource is provided by a remote agent. Since the script is pulled before running, the agent is still fungible;&lt;/li&gt;&#10;&lt;li&gt;The result from service script execution is archived (similar to the way build artifact is stored in Jenkins) in master.&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The architecture of this pipeline now becomes the followings:&lt;/p&gt;&#10;&lt;p class="has-pale-cyan-blue-background-color has-background wp-block-paragraph"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="591px" viewBox="-0.5 -0.5 591 671" style="max-width:100%;max-height:671px;"&gt;&lt;defs&gt;&lt;/defs&gt;&lt;g&gt;&lt;rect x="220" y="0" width="130" height="190" rx="19.5" ry="19.5" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 7px; margin-left: 221px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Vendor&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="285" y="19" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Vendor&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="430" y="390" width="160" height="280" rx="24" ry="24" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 397px; margin-left: 431px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Customer B&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="510" y="409" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Customer B&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="0" y="400" width="160" height="270" rx="24" ry="24" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 407px; margin-left: 1px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Customer A&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="80" y="419" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Customer A&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="240" y="110" width="90" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 125px; margin-left: 241px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;SSH Proxy&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="285" y="129" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;SSH Proxy&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="240" y="30" width="90" height="60" rx="9" ry="9" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 60px; margin-left: 241px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Jenkins (Master)&lt;br&gt;Ansible&lt;br&gt;OpenSSH&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="285" y="64" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Jenkins (Master&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;ellipse cx="285" cy="190" rx="30" ry="30" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 190px; margin-left: 256px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;VPN&lt;br&gt;Gateway&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="285" y="194" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;VPN&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;ellipse cx="150" cy="410" rx="30" ry="30" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 410px; margin-left: 121px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;VPN&lt;br&gt;Gateway&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="150" y="414" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;VPN&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;ellipse cx="430" cy="400" rx="30" ry="30" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 400px; margin-left: 401px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;VPN&lt;br&gt;Gateway&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="430" y="404" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;VPN&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 215 285 C 163 285 150 320 191.6 327 C 150 342.4 196.8 376 230.6 362 C 254 390 332 390 358 362 C 410 362 410 334 377.5 320 C 410 292 358 264 312.5 278 C 280 257 228 257 215 285 Z" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 258px; height: 1px; padding-top: 320px; margin-left: 151px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Internet&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;br&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="280" y="324" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Internet&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="30" y="470" width="100" height="90" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 515px; margin-left: 31px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;agent.jar&lt;br&gt;Ansible&lt;br&gt;OpenSSH&lt;br&gt;Git&lt;br&gt;Python&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="80" y="519" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;agent.jar&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="460" y="470" width="100" height="90" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 515px; margin-left: 461px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;agent.jar&lt;br&gt;Ansible&lt;br&gt;OpenSSH&lt;br&gt;Git&lt;br&gt;Python&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="510" y="519" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;agent.jar&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 282.5 257.65 L 284.58 226.35" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 282.15 262.88 L 279.13 255.67 L 282.5 257.65 L 286.11 256.13 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 284.93 221.12 L 287.95 228.33 L 284.58 226.35 L 280.97 227.87 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 173.61 382.89 L 181.4 363.7" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 171.63 387.75 L 171.03 379.95 L 173.61 382.89 L 177.51 382.58 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 183.38 358.84 L 183.99 366.64 L 181.4 363.7 L 177.5 364 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 406.97 372.68 L 401.42 354.1" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 408.47 377.72 L 403.11 372.01 L 406.97 372.68 L 409.82 370.01 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 399.92 349.07 L 405.28 354.78 L 401.42 354.1 L 398.57 356.78 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 84.98 466.04 L 123.8 435.18" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 80.88 469.3 L 84.18 462.21 L 84.98 466.04 L 88.53 467.69 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 127.91 431.91 L 124.61 439 L 123.8 435.18 L 120.25 433.53 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 456.11 425.28 L 505.1 465.93" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 452.07 421.93 L 459.7 423.7 L 456.11 425.28 L 455.23 429.09 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 509.14 469.29 L 501.52 467.51 L 505.1 465.93 L 505.99 462.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 285 153.63 L 285 146.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 285 158.88 L 281.5 151.88 L 285 153.63 L 288.5 151.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 285 141.12 L 288.5 148.12 L 285 146.37 L 281.5 148.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 285 103.63 L 285 96.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 285 108.88 L 281.5 101.88 L 285 103.63 L 288.5 101.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 285 91.12 L 288.5 98.12 L 285 96.37 L 281.5 98.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;rect x="20" y="590" width="120" height="60" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 620px; margin-left: 21px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Customer Inventory&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="80" y="624" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Customer Inventory&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="450" y="590" width="120" height="60" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 620px; margin-left: 451px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Customer Inventory&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="510" y="624" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Customer Inventory&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 80 583.63 L 80 566.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 80 588.88 L 76.5 581.88 L 80 583.63 L 83.5 581.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 80 561.12 L 83.5 568.12 L 80 566.37 L 76.5 568.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 510 583.63 L 510 566.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 510 588.88 L 506.5 581.88 L 510 583.63 L 513.5 581.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 510 561.12 L 513.5 568.12 L 510 566.37 L 506.5 568.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;ellipse cx="290" cy="345" rx="50" ry="35" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 345px; margin-left: 241px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Git &lt;br&gt;Repository&lt;br&gt;Jenkisfile&lt;br&gt;scripts&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="290" y="349" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Git&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 133.46 509.65 L 236.54 350.35" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 130.61 514.06 L 131.47 506.28 L 133.46 509.65 L 137.35 510.09 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 239.39 345.94 L 238.53 353.72 L 236.54 350.35 L 232.65 349.91 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 343.67 350.2 L 456.33 509.8" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 340.64 345.91 L 347.54 349.61 L 343.67 350.2 L 341.82 353.65 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 459.36 514.09 L 452.46 510.39 L 456.33 509.8 L 458.18 506.35 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;/g&gt;&lt;a transform="translate(0,-5)" xlink:href="https://desk.draw.io/support/solutions/articles/16000042487" target="_blank" rel="noopener noreferrer"&gt;&lt;text text-anchor="middle" font-size="10px" x="50%" y="100%"&gt;Viewer does not support full SVG 1.1&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-configure-agent"&gt;Configure Agent&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Jenkins has a plugin called &lt;a href="https://plugins.jenkins.io/ssh-slaves/"&gt;SSH Build Agent&lt;/a&gt;, that allows you to configure a Linux agent, communicating with Jenkins master in SSH. For Window agent, it uses JNLP to communicate with master, which is outside of our scope of discussion. As I touched on in &lt;a href="https://static.digihunch.com/2020/10/automated-deployment-pipeline-2-of-2/"&gt;previous post&lt;/a&gt;, Jenkins uses its own implementation of SSH protocol to achieve this. This means that it cannot re-use the configurations in ~/.ssh/config and thus the ability to do SSH chaining is eliminated. This is incompatible with our architecture so I have to register Jenkins agent using a different launch method &amp;#8220;Launch agent via execution of command on the master&amp;#8221;. The execution of command on master can still leverage OpenSSH config file. In order to do so, we must copy the agent.jar file to the remote agent first (URL is ${JENKINS_URL}/jnlpJars/agent.jar). Then use SSH command to call the jar file from agent (aka slave) machine. You may add some java argument for troubleshooting. Below is an example configuration for the node.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" width="2658" height="1650" src="https://static.digihunch.com/wp-content/uploads/2020/10/image-6.png" alt="" class="wp-image-1736" style="width:0px"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I shall also note that if the remote agent is a different operating system where the path of bash might be different, then you need to include the directory of bash executable in PATH environment variable. That can be done as in the screenshot above (PATH=${PATH:/usr/bin}). If this is incorrect, you might run into issues when running sh step in Jenkins pipeline. Here is an &lt;a href="https://qiita.com/xishan/items/881f1e02628170801f4a"&gt;article&lt;/a&gt; about this. To translate that page, the symptom of this issue includes:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Error from pipeline execution that says the following, which is very generic:&lt;/li&gt;&#10;&lt;/ul&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;process apparently never started in /home/dhunch/jenkins/workspace/site-remote-job@tmp/durable-b997d26c &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;(running Jenkins temporarily with -Dorg.jenkinsci.plugins.durabletask.BourneShellScript.LAUNCH_DIAGNOSTICS=true might make the problem clearer)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Job status shows:&lt;/li&gt;&#10;&lt;/ul&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;hudson.AbortException: script returned exit code -2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;at org.jenkinsci.plugins.workflow.steps.durable_task.DurableTaskStep$Execution.handleExit(DurableTaskStep.java:659)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;at org.jenkinsci.plugins.workflow.steps.durable_task.DurableTaskStep$Execution.check(DurableTaskStep.java:605)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;at org.jenkinsci.plugins.workflow.steps.durable_task.DurableTaskStep$Execution.run(DurableTaskStep.java:549)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#9;at java.base/java.lang.Thread.run(Thread.java:834)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Threaddump (only available during execution) shows:&lt;/li&gt;&#10;&lt;/ul&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;Thread #6&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at DSL.sh(awaiting process completion in /home/dhunch/jenkins/workspace/site-remote-job/durable-b997d26c; recurrence period: 9543ms; check task scheduled; cancelled? false done? false)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at WorkflowScript.run(WorkflowScript:9)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; at DSL.script(Native Method)&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This issue is tricky because none of the symptoms above make you think about the environment variable defined for the agent, and that the issue does not occur until you actually execute a Jenkins pipeline, usually well after the node agent is registered, and only impacts shell step (sh). It is recommended to test this with sh steps in pipeline.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-configure-repository"&gt;Configure Repository&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Our example job executes service script pulled from SCM, on a remote agent. Then the master pulls the result file to itself. The git repository can be set in Jenkins job, where you specify that the script named Jenkinsfile (from the repo) is the pipeline file that needs to be executed.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1428" height="756" src="https://static.digihunch.com/wp-content/uploads/2020/10/image-5.png" alt="" class="wp-image-1734"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This is fairly simple, but what makes the situation more complex is the following few requirements:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;it&amp;#8217;s the agent node that needs git (installed) and clone to repo;&lt;/li&gt;&#10;&lt;li&gt;the master does not need (and should not attempt to) clone from repo;&lt;/li&gt;&#10;&lt;li&gt;the master needs to do its job without having to pull SCM;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We need to be able to specify whether each step needs to pull from SCM. The following pipeline syntax shows how this is done:&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-groovy" data-lang="groovy"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;def&lt;/span&gt; agent_dir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;initial_value&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pipeline &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agent none&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options &lt;span style="color:#f92672"&gt;{&lt;/span&gt; skipDefaultCheckout&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stages &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stage&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;Execute Job&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agent &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; label &lt;span style="color:#e6db74"&gt;&amp;#39;remote-agent-customer1&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options &lt;span style="color:#f92672"&gt;{&lt;/span&gt; skipDefaultCheckout&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; steps &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#39;Executing job on node&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sh &lt;span style="color:#e6db74"&gt;&amp;#39;whoami &amp;amp;&amp;amp; pwd&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; script &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agent_dir &lt;span style="color:#f92672"&gt;=&lt;/span&gt; sh&lt;span style="color:#f92672"&gt;(&lt;/span&gt;returnStdout: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt; script: &lt;span style="color:#e6db74"&gt;&amp;#39;echo -n ${WORKSPACE}&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// the variable should not include carriage return&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sh &lt;span style="color:#e6db74"&gt;&amp;#34;echo ${agent_dir}&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stage&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;Pull Result&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agent &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; label &lt;span style="color:#e6db74"&gt;&amp;#39;master&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options &lt;span style="color:#f92672"&gt;{&lt;/span&gt; skipDefaultCheckout&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt; &lt;span style="color:#75715e"&gt;// no need to pull scm to this agent&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; steps &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#39;Pulling job below&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sh &lt;span style="color:#e6db74"&gt;&amp;#34;echo ${agent_dir}&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sh &lt;span style="color:#e6db74"&gt;&amp;#34;scp dhunch@site1:\&amp;#34;${agent_dir}\&amp;#34;/result.csv ./&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In this example pipeline file, we declare agent none for the pipeline, then an agent for each specific stage. we also specify the option skipDefaultCheckout as true at the step where pulling from SCM is not needed. This allows us to finish job with multiple agent, and only pull from SCM as needed. This snippet also exemplifies how to declare a variable, assign it from stdout from one agent, and persist the value across ensuing stages.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-store-result"&gt;Store Result&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The reason we run pipeline jobs on this remote agent is because it is sitting in customer network and has local direct access to data. So this is perfect for situation such as data analytical jobs, which access to database on local network and store result. We need to pull the result file back to agent and make it available on Jenkins. This is so similar to &amp;#8220;archive artifact&amp;#8221; task (commonly seen in CI process) that we can simply use its plugin to achieve what we need. Before archive artifact, we need to pull it to local (master), as shown in the example code above. After that, we need another stage to archive the result.&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-groovy" data-lang="groovy"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stage&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;Archive Result&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agent &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; label &lt;span style="color:#e6db74"&gt;&amp;#39;master&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options &lt;span style="color:#f92672"&gt;{&lt;/span&gt; skipDefaultCheckout&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt; &lt;span style="color:#75715e"&gt;// no need to pull scm to this agent&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; steps &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; archiveArtifacts artifacts: &lt;span style="color:#e6db74"&gt;&amp;#39;*.csv&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt;onlyIfSuccessful: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&lt;span style="color:#f92672"&gt;,&lt;/span&gt;fingerprint: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;I believe there is plugins to compress artifacts as well.&lt;/p&gt;&#10;&lt;h2 class="wp-block-heading" id="h-conclusion"&gt;Conclusion&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;At the end I&amp;#8217;d like to reiterate my perception about Jenkins. It is a very generic and adaptive automation platform that originally evolved from use cases in build automation. Due to this original root, many components in Jenkins are named around Continuous Integration use cases, such as the &amp;#8220;build&amp;#8221; button, and the &amp;#8220;archiveArtifacts&amp;#8221; step. These misnomers underplays what Jenkins can potentially do in continuous deployment or other automation scenarios. It is important for automation engineers to understand Jenkins components and plugins, through their functionalities and not by the name, and therefore make creative use of Jenkins as automation engine in all scenarios. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;An alternative to this proposed pipeline would be Ansible Tower, a commercial project based on open-source Ansible, but with nice UI support. Ansible Tower is Ansible oriented, and it does not have everything that Jenkins can do. It should still be a decent alternative given the proposes pipeline uses Ansible a lot.&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/10/automated-deployment-pipeline-2-of-2/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Automated Deployment Pipeline 2 of 3&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/10/host-legacy-application-in-docker-2-of-2/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Host legacy application in Docker 2 of 2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Automated Deployment Pipeline 2 of 3</title><link>https://static.digihunch.com/2020/10/automated-deployment-pipeline-2-of-2/</link><pubDate>Tue, 06 Oct 2020 22:05:00 -0400</pubDate><guid>https://static.digihunch.com/2020/10/automated-deployment-pipeline-2-of-2/</guid><description>&lt;p class="wp-block-paragraph"&gt;In this posting, we continue to discuss Jenkins&amp;#8217; ability to automate deployment routines. Jenkins supports freestyle project out of the box, as well as Pipeline with several plugins. Freestyle project allows user to specify multiple steps on UI. This does not scale well when your entire process involves many steps. As explained on Jenkins&amp;#8217; website:&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;While standard Jenkins “freestyle” jobs support simple continuous integration by allowing you to define sequential tasks in an application lifecycle, they do not create a &lt;strong&gt;persistent record of execution&lt;/strong&gt;, enable one script to address all the steps in a complex workflow, or confer the other advantages of pipelines.&lt;br&gt;In contrast to freestyle jobs, pipelines enable you to define the whole application lifecycle. Pipeline functionality helps Jenkins to support continuous delivery (CD). The Pipeline plugin was built with requirements for a flexible, extensible, and script-based CD workflow capability in mind.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;So although freestyle projects are easy to set up, and can do technically everything that Jenkins pipeline can do, the major advantage of Jenkins Pipeline is the ability to manage multiple-step as code, and version control the pipeline-as-code. Here is some more &lt;a href="https://www.jenkins.io/blog/2017/01/19/converting-conditional-to-pipeline/"&gt;information&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We will start with a freestyle project to understand Jenkins&amp;#8217; ability and then advance to building pipelines.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-freestyle-projects"&gt;Freestyle projects&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As mentioned, Jenkins calls a task a &amp;#8220;build&amp;#8221;, and the build can be triggered in a variety of ways:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Time schedule (with or without parameter)&lt;/li&gt;&#10;&lt;li&gt;Remotely via API&lt;/li&gt;&#10;&lt;li&gt;On completion of other projects&lt;/li&gt;&#10;&lt;li&gt;Poll SCM for changes&lt;/li&gt;&#10;&lt;li&gt;Commit to SCM&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are also several ways to execute a job:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Execute Shell command, batch command or groovy script&lt;/li&gt;&#10;&lt;li&gt;Invoke Ansible adhoc command, playbook or vault&lt;/li&gt;&#10;&lt;li&gt;Conditional on specified boolean value, file existence, etc&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;After the job one can specify post-build jobs, for example:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;start other build projects&lt;/li&gt;&#10;&lt;li&gt;notification of various means&lt;/li&gt;&#10;&lt;li&gt;publishing result file&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In deployment, it is common task to execute a task over SSH, using SSH command or invoke Ansible command with Ansible plugin. The former fits simple command line tasks. For example:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" width="2036" height="738" src="https://static.digihunch.com/wp-content/uploads/2020/10/image-1.png" alt="" class="wp-image-1658" style="width:812px;height:auto"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The Ansible plugin is good for more steps and more complicated inventory hierarchies. This &lt;a href="https://static.digihunch.com/2020/05/revamp-ansible-directory-for-scalability-1-of-2/"&gt;post&lt;/a&gt; includes an example of an inventory involving multiple layers. The other limitation with SSH command is lack of a straightforward configuration to escalate privilege and run remote command. On the other hand, Ansible addressed this with become method. Below is a screenshot &lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" width="950" height="837" src="https://static.digihunch.com/wp-content/uploads/2020/10/image-2.png" alt="" class="wp-image-1659" style="width:785px;height:auto"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In order to use Ansible command, you will also need to specify where the Ansible binary in &lt;a href="https://medium.com/devops-process-and-tools/configure-jenkins-job-with-ansible-jenkins-plugin-to-setup-ci-for-ansible-playbooks-3ed23137d314"&gt;Global Tool Configuration&lt;/a&gt;. You will also need to store vault credential in Jenkins credential store so it&amp;#8217;s not being prompted.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-jenkins-pipeline"&gt;Jenkins Pipeline&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Jenkins pipeline allows one to describe actions in a pipeline in groovy &lt;a href="http://docs.groovy-lang.org/docs/latest/html/documentation/core-domain-specific-languages.html"&gt;Domain Specific Language (DSL)&lt;/a&gt;. There are two styles of pipelines:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;Declarative pipeline&lt;/strong&gt; is identified by a block named &amp;#8216;pipeline&amp;#8217;, it is relatively new and supports the pipeline-as-code concept. It can be stored as Jenkinsfile in code repository or edited in Jenkins&amp;#8217; UI.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Scripted pipeline&lt;/strong&gt; is identified by a block named &amp;#8216;node&amp;#8217;, it is the conventional format and can only be edited in Jenkins&amp;#8217; UI.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To fully understand the two styles of pipelines you also need to know &lt;a href="https://en.wikipedia.org/wiki/Declarative_programming"&gt;declarative programming&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Imperative_programming"&gt;imperative programming&lt;/a&gt;. Read &lt;a href="https://www.jenkins.io/doc/book/pipeline/syntax/"&gt;this&lt;/a&gt; instruction for a better explanation. &lt;a href="https://e.printstacktrace.blog/jenkins-scripted-pipeline-vs-declarative-pipeline-the-4-practical-differences/"&gt;Here&lt;/a&gt; is another good one that focus on their differences.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Jenkins&amp;#8217; plugin provides UI components for user to input information (e.g. Invoke Ansible Command), now with Jenkins pipelines, plugins can provide step functions in order to help Jenkins user. &lt;a href="https://www.jenkins.io/doc/pipeline/steps/"&gt;This&lt;/a&gt; page from Jenkins lists the most common ones, many of which requires plugin installation. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;One example of step function is &lt;a href="https://www.jenkins.io/doc/pipeline/steps/ssh-steps/"&gt;SSH Pipeline Steps&lt;/a&gt;. It allows one to issue SSH connection from Jenkinsfile. However, in our deployment scenarios, it has some limitations:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;Unable to match a group of host by specific pattern&lt;/li&gt;&#10;&lt;li&gt;Cannot use host name aliases&lt;/li&gt;&#10;&lt;li&gt;SSH tunneling is not supported&lt;/li&gt;&#10;&lt;li&gt;No means of privilege escalation&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Out of these 1 through 3 are due to the fact that SSH step function does not use the OpenSSH configuration on the machine. The&amp;nbsp;&lt;a href="https://wiki.jenkins-ci.org/display/JENKINS/SSH+Slaves+plugin"&gt;jenkins-ssh-slaves plugin&lt;/a&gt;&amp;nbsp;uses&amp;nbsp;&lt;a href="https://github.com/jenkinsci/trilead-ssh2"&gt;trilead SSH2 implementation&lt;/a&gt;&amp;nbsp;written in Java. Only OpenSSH implementation uses ~/.ssh/config file. This creates problem whenever SSH tunneling is needed. For example, to register a remote slave node via SSH tunneling, we need to select &amp;#8220;Launch agent via &lt;a href="https://support.cloudbees.com/hc/en-us/articles/234491548-Run-SSH-Agent-using-a-command-on-Master"&gt;execution of command on the master&lt;/a&gt;&amp;#8221; instead of &amp;#8220;Launch agent via SSH&amp;#8221; as launch method. &lt;a href="https://support.cloudbees.com/hc/en-us/articles/234491548-Run-SSH-Agent-using-a-command-on-Master"&gt;Here&lt;/a&gt; is an instruction and below is what it looks like:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" width="727" height="405" src="https://static.digihunch.com/wp-content/uploads/2020/10/image-3.png" alt="" class="wp-image-1698" style="width:755px;height:auto"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Similarly, if we use ssh-agent plugin as tool for deployment, we cannot use any configuration made by OpenSSH. Therefore Ansible in Jenkins Pipeline is a better tool for deployment because it can use OpenSSH.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-pipelines-with-ansible"&gt;Pipelines with Ansible&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In this section I demonstrate the use of Ansible playbook and adhoc command in pipeline through two examples. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In example 1, the job pulls authorized key file from SCM, and then use a playbook from SCM, to push the key file to all servers in the specified inventory. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Here is the playbook file for example 1:&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;---&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Example:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# ansible-playbook -l all -i ~/ansible/inventories/bh.yml push-key.yml --ask-vault-pass&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;- name: push key to target&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hosts: all&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tasks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - name: sync key to host&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; copy:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; src: &amp;#34;{{authorized_keys_src}}&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dest: &amp;#34;/home/dhunch/.ssh/authorized_keys&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; force: yes&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; mode: 0600&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Here is the pipeline script (note ampersand is mistakenly displayed as &amp;amp;amp; in the box below):&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-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;import&lt;/span&gt; java.net.URLEncoder;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pipeline {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agent any&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; options {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; skipDefaultCheckout(&lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; environment {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; BITBUCKET_CREDS &lt;span style="color:#f92672"&gt;=&lt;/span&gt; credentials(&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;bitbucket&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;) &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;//BITBUCKET_CREDS_USR and BITBUCKET_CREDS_PSW are set&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; BITBUCKET_CREDS_USR &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;${BITBUCKET_CREDS_USR}&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; BITBUCKET_CREDS_PSW &lt;span style="color:#f92672"&gt;=&lt;/span&gt; URLEncoder.&lt;span style="color:#a6e22e"&gt;encode&lt;/span&gt;(&lt;span style="color:#e6db74"&gt;&amp;#34;${BITBUCKET_CREDS_PSW}&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;UTF-8&amp;#34;&lt;/span&gt;) &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// if password contains special character we need to url encode it. e.g. @-&amp;gt;%40&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stages {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stage(&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;Start&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; steps {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Starting pipeline ...&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; deleteDir()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stage(&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;Prep&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; steps{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; wrap(&lt;span style="color:#f92672"&gt;[&lt;/span&gt;$class: &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;MaskPasswordsBuildWrapper&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;, varPasswordPairs: &lt;span style="color:#f92672"&gt;[[&lt;/span&gt;password: &lt;span style="color:#e6db74"&gt;&amp;#34;${BITBUCKET_CREDS_PSW}&amp;#34;&lt;/span&gt;, var: &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;RANDOM&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;]]]&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// MaskPasswordsBuildWrapper requires Mask Passwords Plugin and is to mask specific string in console output. &lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Otherwise BITBUCKET_CREDS_PSW will display in the clear&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sh &lt;span style="color:#e6db74"&gt;&amp;#34;git init &amp;amp;&amp;amp; git config core.sparsecheckout true&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sh &lt;span style="color:#e6db74"&gt;&amp;#34;git remote add origin https://$BITBUCKET_CREDS_USR:${BITBUCKET_CREDS_PSW}@bitbucket.org/vendorcompoany/configmanagerepo.git&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sh &lt;span style="color:#e6db74"&gt;&amp;#34;echo &amp;#39;public_keys/*&amp;#39; &amp;gt;&amp;gt; .git/info/sparse-checkout&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#e6db74"&gt;&amp;#34;Downloading key file&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sh &lt;span style="color:#e6db74"&gt;&amp;#34;git pull --depth=1 origin master&amp;#34;&lt;/span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stage(&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;Deploy &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; Site 1&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; steps {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; Deploying &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; Site 1 ...&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ansiblePlaybook (&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; installation: &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;Ansible on Mac&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; playbook: &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;${WORKSPACE}&lt;span style="color:#f92672"&gt;/&lt;/span&gt;public_keys&lt;span style="color:#f92672"&gt;/&lt;/span&gt;push&lt;span style="color:#f92672"&gt;-&lt;/span&gt;key.&lt;span style="color:#a6e22e"&gt;yml&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; inventory: &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;~/&lt;/span&gt;ansible&lt;span style="color:#f92672"&gt;/&lt;/span&gt;inventories&lt;span style="color:#f92672"&gt;/&lt;/span&gt;site1.&lt;span style="color:#a6e22e"&gt;yml&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; vaultCredentialsId: &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;ansible&lt;span style="color:#f92672"&gt;-&lt;/span&gt;vault&lt;span style="color:#f92672"&gt;-&lt;/span&gt;pass&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; extraVars: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;authorized_keys_src: &lt;span style="color:#e6db74"&gt;&amp;#34;$WORKSPACE/public_keys/authorized_keys&amp;#34;&lt;/span&gt;,&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; Deployed &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; Site 1 ...&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stage(&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;Deploy &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; Site 2&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; steps {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; Deploying &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; Site 2 ...&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ansiblePlaybook (&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; installation: &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;Ansible on Mac&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; playbook: &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;${WORKSPACE}&lt;span style="color:#f92672"&gt;/&lt;/span&gt;public_keys&lt;span style="color:#f92672"&gt;/&lt;/span&gt;push&lt;span style="color:#f92672"&gt;-&lt;/span&gt;key.&lt;span style="color:#a6e22e"&gt;yml&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; inventory: &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;~/&lt;/span&gt;ansible&lt;span style="color:#f92672"&gt;/&lt;/span&gt;inventories&lt;span style="color:#f92672"&gt;/&lt;/span&gt;site2.&lt;span style="color:#a6e22e"&gt;yml&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; vaultCredentialsId: &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;ansible&lt;span style="color:#f92672"&gt;-&lt;/span&gt;vault&lt;span style="color:#f92672"&gt;-&lt;/span&gt;pass&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; extraVars: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;authorized_keys_src: &lt;span style="color:#e6db74"&gt;&amp;#34;$WORKSPACE/public_keys/authorized_keys&amp;#34;&lt;/span&gt;,&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; Deployed &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; Site 2 ...&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stage(&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;Deploy &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; Site 3&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; steps {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; Deploying &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; Site 3 ...&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ansiblePlaybook (&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; installation: &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;Ansible on Mac&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; playbook: &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;${WORKSPACE}&lt;span style="color:#f92672"&gt;/&lt;/span&gt;public_keys&lt;span style="color:#f92672"&gt;/&lt;/span&gt;push&lt;span style="color:#f92672"&gt;-&lt;/span&gt;key.&lt;span style="color:#a6e22e"&gt;yml&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; inventory: &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;~/&lt;/span&gt;ansible&lt;span style="color:#f92672"&gt;/&lt;/span&gt;inventories&lt;span style="color:#f92672"&gt;/&lt;/span&gt;site3.&lt;span style="color:#a6e22e"&gt;yml&lt;/span&gt;&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; vaultCredentialsId: &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;ansible&lt;span style="color:#f92672"&gt;-&lt;/span&gt;vault&lt;span style="color:#f92672"&gt;-&lt;/span&gt;pass&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; extraVars: &lt;span style="color:#f92672"&gt;[&lt;/span&gt;authorized_keys_src: &lt;span style="color:#e6db74"&gt;&amp;#34;$WORKSPACE/public_keys/authorized_keys&amp;#34;&lt;/span&gt;,&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; )&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;&amp;gt;&lt;/span&gt; Deployed &lt;span style="color:#66d9ef"&gt;to&lt;/span&gt; Site 3 ...&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; post {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; always {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; cleanWs()&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In this example, we pull a sub-directory from git repo. We use two tricks to minimize amount of traffic. First, we use git pull with depth=1 so only the required recent commits are pulled, not the entire history. Second we use sparse checkout to get result from a sub-directory, not the entire repo.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When connecting to repo, password is required. We pull the credential from Jenkins&amp;#8217; credential store and they are masked by default. However, the password must be converted to URL string when used in git remote add origin. Otherwise if the password contains special character the URL will not work. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This modification to password brings about another challenge, password masking during the job execution. We will have to build our own wrapper function using class &lt;em&gt;MaskPasswordsBuildWrapper&lt;/em&gt; in order to mask any variable.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In example 2, we wrap an Ansible step function to call adhoc command to check version on all hosts. Here is the pipeline script:&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;def HunchVersionQuery(pattern, siteinventory){&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; step([&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; $class: &amp;#39;AnsibleAdHocCommandBuilder&amp;#39;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ansibleName: &amp;#39;Ansible on Mac&amp;#39;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; inventory: [$class: &amp;#39;InventoryPath&amp;#39;,path: siteinventory],&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hostPattern: pattern,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; module: &amp;#39;shell&amp;#39;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; command: &amp;#39;cat /etc/*release&amp;#39;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; forks: 1,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; vaultCredentialsId: &amp;#39;ansible-vault-pass&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ]);&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pipeline {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; agent any&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stages {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stage(&amp;#39;Start&amp;#39;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; steps {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; echo &amp;#39;Staring Pipeline&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stage(&amp;#39;Query Site1&amp;#39;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; steps { HunchVersionQuery(&amp;#39;*app&amp;#39;,&amp;#39;~/ansible/inventories/site1.yml&amp;#39;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stage(&amp;#39;Query Site2&amp;#39;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; steps { HunchVersionQuery(&amp;#39;*app&amp;#39;,&amp;#39;~/ansible/inventories/site2.yml&amp;#39;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; stage(&amp;#39;Query Site3&amp;#39;) {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; steps {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;HunchVersionQuery(&amp;#39;*app&amp;#39;,&amp;#39;~/ansible/inventories/site3.yml&amp;#39;)&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Because &lt;a href="https://www.jenkins.io/doc/pipeline/steps/ansible/"&gt;Ansible plugin&lt;/a&gt; does not provide a warpper function for adhoc command step, we will have to build our own wrapper function in the above code.&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/09/automated-deployment-pipeline-1-2/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Automated Deployment Pipeline 1 of 3&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/10/automated-deployment-pipeline-3-of-3/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Automated Deployment Pipeline 3 of 3&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Automated Deployment Pipeline 1 of 3</title><link>https://static.digihunch.com/2020/09/automated-deployment-pipeline-1-2/</link><pubDate>Wed, 30 Sep 2020 22:04:00 -0400</pubDate><guid>https://static.digihunch.com/2020/09/automated-deployment-pipeline-1-2/</guid><description>&lt;h3 class="wp-block-heading"&gt;The business case&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;You launched a software application. You installed it on two customer sites. You support the application mostly by SSH to customer server and run Bash commands, or slightly better, Bash scripts. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The product is a hit to the market. You hired 20 support specialists in a customer service department. The dream client came through: an enterprise giving you a fleet of 100 servers to deploy your application on.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;More staff, more business, more installations, more incidents, but the same old command driven steps. Problems:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;Non-standard support procedures. Every one takes notes and everyone&amp;#8217;s notes are slightly different.&lt;/li&gt;&lt;li&gt;Information sharing among team members are ad hoc, and at high level.&lt;/li&gt;&lt;li&gt;Post-mortem discussion is driven by memory and command fragments, instead of evidence end-to-end&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If that looks like your organization, chances are you also suffer from some secondary damages over the long term, such as:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;Downtime resolutions rely on the knowledgeable few&lt;/li&gt;&lt;li&gt;Documentation helps. But it never catches up to the latest version of application&lt;/li&gt;&lt;li&gt;Lack of auditing of commands during support&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I propose an automation scheme to existing support and deployment practice. This automation scheme combines a suite of common technologies, such as Bash, Python, Ansible, OpenSSH and Jenkins. The automation allows the department to, either fully or partially, operationalize the steps in support and deployment, and eventually shift towards agile practice. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Bash, Python and Ansible&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Bash script is based on shell command, perfect for running critical system tasks such as volume management. When it turns into a script, it can be cumbersome, especially with complex data structure. Python, as a tool for system administration, is a good complement to that.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Python 2 comes with most Linux distributions, and is also a dependency of other built-in tools such as YUM. Python3 can be installed easily from default YUM repositories. Both Python2 and Python3 can exist on the same operating system, although new module development are now shifted to Python3. Python&amp;#8217;s syntax is very simple and offers object-oriented programming ability. Moreover, there is an entire open-source community behind Python, which offers modules in every aspect of IT (for example, Datastax has a &lt;a href="https://static.digihunch.com/2020/06/iterate-through-cassandra-table-with-datastax-python-driver/"&gt;driver module&lt;/a&gt; for connecting to Cassandra). Those modules are installed with PIP tool, or PIP3 for python3.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Both bash and Python executes on local machine. To run them on remote servers over SSH. You want to have a list of target hosts, and specify which one to execute the script against. This is where Ansible comes in handy. Ansible is superior in the following aspects:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;Free and open-source, with commercial alternative (Towers);&lt;/li&gt;&lt;li&gt;Inventory management (inventory);&lt;/li&gt;&lt;li&gt;Desire state engine (roles) &lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Ansible is built on Python and is agent-less. Connectivity to remote host is done via secure shell so it can take advantage of existing SSH configurations. Job execution on the target machine is done through Python. With Python you can also develop custom module in Ansible. For some use cases in customer support with Ansible, refer to my two &lt;a href="https://static.digihunch.com/2020/05/revamp-ansible-directory-for-scalability-1-of-2/"&gt;previous postings&lt;/a&gt; about Ansible at scale.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Jenkins&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The tools above forms a package for automation. The issue is that all of them are command-line based. Any task that requires Ansible requires the IT professional craft up long command, such as running playbook, executing a role, or ad-hoc command. This is inconvenient when a task needs to be done during an incident. Such tasks also require trained professional with the relevant skills.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;These tasks can be stored in, or initiated by &lt;a href="https://www.jenkins.io/"&gt;Jenkins&lt;/a&gt;. Although Jenkins is well known for build automation in continuous integration, it is automation engine for any command-line based IT tasks. The button to start such tasks in Jenkins UI is called &amp;#8220;Build&amp;#8221;, which is also a misnomer that underplays Jenkins&amp;#8217; versatility: building application from source code is just one of the many IT tasks that involves multiple long running commands. In this and next article we introduce Jenkins as an engine for deployment automation. &lt;/p&gt;&#10;&lt;p class="has-text-align-center has-background wp-block-paragraph" style="background-color:#d5edf7"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="587" viewBox="-0.5 -0.5 587 567" style="max-width:100%;max-height:567px;"&gt;&lt;defs&gt;&lt;filter id="dropShadow"&gt;&lt;feGaussianBlur in="SourceAlpha" stdDeviation="1.7" result="blur"&gt;&lt;/feGaussianBlur&gt;&lt;feOffset in="blur" dx="3" dy="3" result="offsetBlur"&gt;&lt;/feOffset&gt;&lt;feFlood flood-color="#3D4574" flood-opacity="0.4" result="offsetColor"&gt;&lt;/feFlood&gt;&lt;feComposite in="offsetColor" in2="offsetBlur" operator="in" result="offsetBlur"&gt;&lt;/feComposite&gt;&lt;feBlend in="SourceGraphic" in2="offsetBlur"&gt;&lt;/feBlend&gt;&lt;/filter&gt;&lt;/defs&gt;&lt;g filter="url(#dropShadow)"&gt;&lt;rect x="220" y="0" width="130" height="190" rx="19.5" ry="19.5" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 128px; height: 1px; padding-top: 7px; margin-left: 221px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Vendor&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="285" y="19" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Vendor&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="420" y="390" width="160" height="160" rx="24" ry="24" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 397px; margin-left: 421px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Customer B&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="500" y="409" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Customer B&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="0" y="400" width="160" height="160" rx="24" ry="24" fill="#f5f5f5" stroke="#666666" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 158px; height: 1px; padding-top: 407px; margin-left: 1px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #333333; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Customer A&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="80" y="419" fill="#333333" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Customer A&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="240" y="110" width="90" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 125px; margin-left: 241px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;SSH Proxy&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="285" y="129" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;SSH Proxy&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="240" y="30" width="90" height="60" rx="9" ry="9" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 88px; height: 1px; padding-top: 60px; margin-left: 241px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Jenkins&lt;br&gt;Ansible&lt;br&gt;OpenSSH&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="285" y="64" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Jenkins&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;ellipse cx="285" cy="190" rx="30" ry="30" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 190px; margin-left: 256px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;VPN&lt;br&gt;Gateway&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="285" y="194" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;VPN&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;ellipse cx="150" cy="410" rx="30" ry="30" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 410px; margin-left: 121px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;VPN&lt;br&gt;Gateway&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="150" y="414" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;VPN&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;ellipse cx="430" cy="400" rx="30" ry="30" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/ellipse&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 400px; margin-left: 401px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;VPN&lt;br&gt;Gateway&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="430" y="404" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;VPN&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 247.5 280 C 217.5 280 210 310 234 316 C 210 329.2 237 358 256.5 346 C 270 370 315 370 330 346 C 360 346 360 322 341.25 310 C 360 286 330 262 303.75 274 C 285 256 255 256 247.5 280 Z" fill="#ffffff" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 148px; height: 1px; padding-top: 310px; margin-left: 211px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Internet&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="285" y="314" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Internet&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="20" y="470" width="120" height="60" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 500px; margin-left: 21px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Server Fleet Managed by Vendor&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="80" y="504" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Server Fleet Managed&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="440" y="470" width="120" height="60" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 500px; margin-left: 441px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Server Fleet Managed by Vendor&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="500" y="504" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Server Fleet Managed&amp;#8230;&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 286.02 255.63 L 285.18 226.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 286.17 260.88 L 282.47 253.99 L 286.02 255.63 L 289.47 253.79 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 285.03 221.12 L 288.73 228.01 L 285.18 226.37 L 281.73 228.21 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 176.2 384.82 L 224.52 346.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 172.09 388.09 L 175.39 380.99 L 176.2 384.82 L 179.74 386.47 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 228.63 343.1 L 225.33 350.19 L 224.52 346.37 L 220.97 344.72 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 403.86 374.76 L 358.93 338.03" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 407.92 378.08 L 400.29 376.36 L 403.86 374.76 L 404.72 370.94 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 354.87 334.71 L 362.5 336.43 L 358.93 338.03 L 358.07 341.85 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 84.98 466.04 L 123.8 435.18" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 80.88 469.3 L 84.18 462.21 L 84.98 466.04 L 88.53 467.69 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 127.91 431.91 L 124.61 439 L 123.8 435.18 L 120.25 433.53 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 455.72 425.72 L 495.5 465.5" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 452 422 L 459.43 424.48 L 455.72 425.72 L 454.48 429.43 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 499.21 469.21 L 491.78 466.73 L 495.5 465.5 L 496.73 461.78 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 285 153.63 L 285 146.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 285 158.88 L 281.5 151.88 L 285 153.63 L 288.5 151.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 285 141.12 L 288.5 148.12 L 285 146.37 L 281.5 148.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 285 103.63 L 285 96.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 285 108.88 L 281.5 101.88 L 285 103.63 L 288.5 101.88 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 285 91.12 L 288.5 98.12 L 285 96.37 L 281.5 98.12 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;/g&gt;&lt;switch&gt;&lt;g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;/g&gt;&lt;a transform="translate(0,-5)" xlink:href="https://desk.draw.io/support/solutions/articles/16000042487" target="_blank" rel="noopener noreferrer"&gt;&lt;text text-anchor="middle" font-size="10px" x="50%" y="100%"&gt;Viewer does not support full SVG 1.1&lt;/text&gt;&lt;/a&gt;&lt;/switch&gt;&lt;/svg&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The infrastructure architecture is diagramed as above, and with the connection across Internet, the target hosts must be hardened properly in the following aspects:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;Connectivity to remote host is via SSH chaining, through an SSH proxy;&lt;/li&gt;&lt;li&gt;Root login must be disabled for remote session or by password;&lt;/li&gt;&lt;li&gt;Service user may be shared, but must be authenticated by individual RSA key pair;&lt;/li&gt;&lt;li&gt;Service user connected remotely needs to escalate privilege by su if needed;&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I want to make a theoretical distinction between our topic here and continuous deployment. We simply focus on the technical side of deployment automation. Essentially automating a few bash scripts. On the other hand, a continuous deployment process is an extension to an existing continuous integration pipeline, with the vision to streamline the process end-to-end from code commit to production rollout. Implementing CI/CD pipelines should be approached as an organizational program rather than an individual technical initiative. &lt;a href="https://www.redhat.com/en/blog/integrating-ansible-jenkins-cicd-process"&gt;Here&lt;/a&gt; is a good technical overview on CI/CD pipeline with Jenkins and Ansible.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Security&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The security mechanism of this system is based on OpenSSH because the connectivity between servers are through SSH chaining. RSA key authentication must be used in order to encrypt traffic with password-less login. Connection to an SSH host can be done through a proxy server. Below is an example of SSH configuration:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Include customer1.config&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Include customer2.config&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Host *&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; IdentityFile ~/.ssh/id_rsa&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ServerAliveInterval &lt;span style="color:#ae81ff"&gt;60&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ServerAliveCountMax &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Compression yes&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ControlPersist 3h&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ControlPath ~/.ssh/sockets/%r@%h-%p&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Host gateway&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Hostname support.digihunch.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; User jdoe&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Port &lt;span style="color:#ae81ff"&gt;2223&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Host customer-server-0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Hostname 192.168.201.12&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; User support&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ProxyCommand ssh -W %h:%p gateway&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Open SSH configuration file (~/.ssh/config) needs to be configured properly with useful host names and aliases. To prevent the config files from growing too long, include statement can be used to reference other configuration file (available with OpenSSH v7.3 sp1 and up). &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The host names (as well as aliases) listed in SSH configuration can be directly referenced in Ansible inventory, allowing Ansible (and Jenkins) to reference site by alias and connect to target host through proxy.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Plugins&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Jenkins has a community that develops a variety of plugins, which makes Jenkins the most powerful automation platform. Here are some examples of useful plugins:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;Audit Trail: output job execution history to file or Elasticsearch;&lt;/li&gt;&lt;li&gt;Credentials: stores credentials in Jenkins;&lt;/li&gt;&lt;li&gt;Pipeline: build declarative (new) or scripted (old) pipeline for Jenkins jobs;&lt;/li&gt;&lt;li&gt;Simple Theme: just a theme but allows console output to be dark (using CSS);&lt;/li&gt;&lt;li&gt;Job Configuration History: job configuration audit;&lt;/li&gt;&lt;li&gt;Mask password: mask variables (including password) from console output &lt;/li&gt;&lt;li&gt;Ansible: invokes ad-hoc commands and playbooks&lt;/li&gt;&lt;li&gt;SSH agent, SSH pipeline steps, SSH credentials: features related in SSH in Jenkins pipelines.&lt;/li&gt;&lt;li&gt;Purge Job History: purge all of build history, or purge&lt;a href="https://support.cloudbees.com/hc/en-us/articles/215549798-Best-Strategy-for-Disk-Space-Management-Clean-Up-Old-Builds"&gt; by time &lt;/a&gt;and number of old builds.&lt;/li&gt;&lt;li&gt;Parameterized Scheduler: schedule to run a job and provide parameter&lt;/li&gt;&lt;li&gt;Workspace cleanup: clean up workspace when invoked.&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the next article, we will go over some common job configurations.&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/09/log-file-navigator-lnav/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Log file navigator (lnav)&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/10/automated-deployment-pipeline-2-of-2/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Automated Deployment Pipeline 2 of 3&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Log file navigator (lnav)</title><link>https://static.digihunch.com/2020/09/log-file-navigator-lnav/</link><pubDate>Wed, 23 Sep 2020 21:03:00 -0400</pubDate><guid>https://static.digihunch.com/2020/09/log-file-navigator-lnav/</guid><description>&lt;p class="wp-block-paragraph"&gt;I&amp;#8217;ve used a number of log viewers in command terminal, on MacOS and Linux server. I read system logs, log4j formats, as well as json formats. Unfortunately, I have not found an ideal (free) log viewer, either on UI or in command terminal.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Out of those I tried lnav is one of the better ones. It&amp;#8217;s been around for more than 10 years and is configurable for a variety of formats. It is available in EPEL-repository for Linux and home brew for Mac.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For example, if our log (produced by log4j) looks like this:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-10-06 20:59:25,471,DEBUG,org.dcm4che2.net.Association - &lt;span style="color:#f92672"&gt;[&lt;/span&gt;platform-dicomServer-44104-574917&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Association&lt;span style="color:#f92672"&gt;(&lt;/span&gt;552550&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: start ARTIM 5000ms&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-10-06 20:59:25,471,DEBUG,org.dcm4che2.net.Association - &lt;span style="color:#f92672"&gt;[&lt;/span&gt;platform-dicomServer-44104-574917&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Association&lt;span style="color:#f92672"&gt;(&lt;/span&gt;552550&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: Client closed connecti&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;on without sending data&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-10-06 20:59:25,471,DEBUG,org.dcm4che2.net.Association - &lt;span style="color:#f92672"&gt;[&lt;/span&gt;platform-dicomServer-44104-574917&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Association&lt;span style="color:#f92672"&gt;(&lt;/span&gt;552550&lt;span style="color:#f92672"&gt;)&lt;/span&gt; enter state: Sta1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-10-06 20:59:25,471,INFO,org.dcm4che2.net.Association - &lt;span style="color:#f92672"&gt;[&lt;/span&gt;platform-dicomServer-44104-574917&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Association&lt;span style="color:#f92672"&gt;(&lt;/span&gt;552550&lt;span style="color:#f92672"&gt;)&lt;/span&gt;: close Socket&lt;span style="color:#f92672"&gt;[&lt;/span&gt;addr&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/10.100.101.10,port&lt;span style="color:#f92672"&gt;=&lt;/span&gt;24976,localport&lt;span style="color:#f92672"&gt;=&lt;/span&gt;44104&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-10-06 20:59:25,471,DEBUG,org.dcm4che2.net.AssociationReaper - &lt;span style="color:#f92672"&gt;[&lt;/span&gt;platform-dicomServer-44104-574917&lt;span style="color:#f92672"&gt;]&lt;/span&gt; Stop check &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; idle Association&lt;span style="color:#f92672"&gt;(&lt;/span&gt;552550&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;We can introduce custom formatting, for example:&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-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;dapp&amp;#34;&lt;/span&gt; : {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;title&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;dapp log4j format&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;description&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;dapp log4j format&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;regex&amp;#34;&lt;/span&gt; : {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;dapp&amp;#34;&lt;/span&gt; : {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;pattern&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;^(?&amp;lt;timestamp&amp;gt;\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2},\\d{3}),(?&amp;lt;level&amp;gt;\\w+),(?&amp;lt;component&amp;gt;[\\w-.]+) - \\[(?&amp;lt;thread&amp;gt;[^ ]+)\\] (?&amp;lt;body&amp;gt;.*)$&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;level-field&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;level&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;level&amp;#34;&lt;/span&gt; : {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;error&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;ERROR&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;warning&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;WARN&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;info&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;INFO&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;debug&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;DEBUG&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;value&amp;#34;&lt;/span&gt; : {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;level&amp;#34;&lt;/span&gt; : { &lt;span style="color:#e6db74"&gt;&amp;#34;kind&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;identifier&amp;#34;&lt;/span&gt; : &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;component&amp;#34;&lt;/span&gt; : { &lt;span style="color:#e6db74"&gt;&amp;#34;kind&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;identifier&amp;#34;&lt;/span&gt; : &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;thread&amp;#34;&lt;/span&gt; : { &lt;span style="color:#e6db74"&gt;&amp;#34;kind&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;identifier&amp;#34;&lt;/span&gt; : &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;body&amp;#34;&lt;/span&gt; : { &lt;span style="color:#e6db74"&gt;&amp;#34;kind&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;string&amp;#34;&lt;/span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;highlights&amp;#34;&lt;/span&gt; : {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;DIMSE&amp;#34;&lt;/span&gt; : {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;pattern&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;A-(ASSOCIATE-(RQ|AC)|RELEASE-(RQ|RP)|ABORT)|C-(STORE|MOVE|FIND|ECHO)-(RQ|RSP)&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;color&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;Red&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;sample&amp;#34;&lt;/span&gt; : &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;line&amp;#34;&lt;/span&gt; : &lt;span style="color:#e6db74"&gt;&amp;#34;2020-10-06 12:00:28,500,INFO,dicom.dicom-main - [main] Start listening on port 44104&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Save the content above as ~/.lnav/formats/installed/dapp.json, then load the log file with lnav, lnav will display the log by presenting columns in different colours.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1622" height="237" src="https://static.digihunch.com/wp-content/uploads/2020/10/image.png" alt="" class="wp-image-1616"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;One of the default behaviours is highlighting the IPv4 address, as shown above. This behaviour is however, not optional and currently cannot be turned off, which is reported &lt;a href="https://github.com/tstack/lnav/issues/783"&gt;here&lt;/a&gt;.&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/09/spark-cassandra-and-python/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Spark, Cassandra and Python&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/09/automated-deployment-pipeline-1-2/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Automated Deployment Pipeline 1 of 3&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Kafka high-level Overview</title><link>https://static.digihunch.com/2020/07/zookeeper-and-kafka-overview/</link><pubDate>Tue, 21 Jul 2020 23:19:00 -0400</pubDate><guid>https://static.digihunch.com/2020/07/zookeeper-and-kafka-overview/</guid><description>&lt;h3 class="wp-block-heading" id="h-zookeeper"&gt;Zookeeper&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;General definition of distributed system: a software system that is composed of &lt;strong&gt;independent &lt;/strong&gt;computing entities linked &lt;strong&gt;together &lt;/strong&gt;by a computer network whose components communicate and coordinate with each other to achieve a common computational goal. Implementing coordination among components of a distributed system is hard. For example, designated master node becomes single point of failure; cluster needs to detect availability of new nodes as it joins cluster.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Zookeeper is designed to &lt;strong&gt;simplify cluster coordination&lt;/strong&gt;. Zookeeper implements key aspects in cluster coordination, such as distributed consensus, group management, presence protocols and leader election. In order to coordinate a cluster, zookeeper itself also runs in its own cluster, called &lt;strong&gt;ensemble&lt;/strong&gt;. Zookeeper exposes a simple but powerful interface of primitives. Applications can be designed on these primitives implemented through ZooKeeper APIs to solve the problems of distributed synchronization, cluster configuration management, group membership, etc.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://zookeeper.apache.org/doc/r3.4.6/images/zkservice.jpg" alt=""/&gt;&lt;figcaption class="wp-element-caption"&gt;Zookeeper Ensemble&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Clients can connect to a Zookeeper service by connecting to any member of the ensemble. The members of the ensemble are aware of each other&amp;#8217;s state. As long as a majority of the nodes are available, the service will be available. &lt;strong&gt;Zookeeper cli (zkCli.sh)&lt;/strong&gt; can be used to connect to Zookeeper server. they can be downloaded from &lt;a href="https://zookeeper.apache.org/releases.html"&gt;here&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Zookeeper is integrated with many other services apart from Kafka, such as Nifi and Hadoop.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-kafka"&gt;&lt;strong&gt;Kafka&lt;/strong&gt;&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://kafka.apache.org/"&gt;Kafka &lt;/a&gt;is a messaging system that is horizontally scalable, fault tolerant. It can also serve as queue storage system and stream processing system. It is distributed and use Zookeeper for cluster coordination. Each node is called a broker.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://kafka.apache.org/25/images/log_anatomy.png" alt=""/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Topics &lt;/strong&gt;in Kafka (think of table in database) is a category or feed name to which messages (records) are published. Topic is broken up into ordered commit logs called partitions. Each partition has an ID. Each message in a partition is assigned an offset. Topics that are created in Kafka are distributed across brokers based on the partition, replication, and other factors. Each partition is replicated across several brokers depending on replication factor. For each partition, Kafka elect one replica as the leader of partition.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Writes to a partition is generally sequential. Reading messages can either be from the beginning, or rewind or skip to any port in partition given an offset value. Data in a topic is retained for a configurable period of time. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A &lt;strong&gt;message &lt;/strong&gt;is a unit of data in Kafka, in the format of key-value pair. A key is used to control the message that is to be written to partitions. Messages with the same keys are always written to the same partition (hash map)&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A &lt;strong&gt;producer &lt;/strong&gt;publishes new message to a topic. Producers do not care which partition the message is written to and will balance messages over every partition of a topic evenly. Directing messages to a partition is done using the message key and a partitioner, this will generate a hash of the key and map it to a partition.&lt;/p&gt;&#10;&lt;figure class="wp-block-image is-resized"&gt;&lt;img loading="lazy" decoding="async" src="https://kafka.apache.org/25/images/log_consumer.png" alt="" width="370" height="225"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A &lt;strong&gt;consumer &lt;/strong&gt;is subscribed to one or more topics and read messages sequentially. The consumer keeps track of messages it has consumed by keeping track on the offset of the message. The offset is a bit of metadata (an integer value that continually increases) that kafka adds to each message. Each partition has a unique offset which is stored with the offset of the last consumed message. A consumer can stop and start without losing its current state.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A Kafka &lt;strong&gt;broker &lt;/strong&gt;is designed to operate as part of a cluster. One broker in the cluster also function as the cluster&amp;#8217;s controller, which is responsible for administrative operations such as: assigning partitions to brokers; monitoring for broker failures in cluster. A particular partition is owned by a broker and that broker is called the leader of the partition.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;All consumers and producers operating on that partition must connect to the leader.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Kafka cluster may replicate across cluster using MirrorMaker.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Reference: &lt;strong&gt;Kafka: The Definitive Guide: Real-Time Data and Stream Processing at Scale&lt;/strong&gt;&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" src="https://static.digihunch.com/wp-content/uploads/2023/01/kafka-780x1024.jpeg" alt="" class="wp-image-7913" width="207" height="272" srcset="https://static.digihunch.com/wp-content/uploads/2023/01/kafka-780x1024.jpeg 780w, https://static.digihunch.com/wp-content/uploads/2023/01/kafka-229x300.jpeg 229w, https://static.digihunch.com/wp-content/uploads/2023/01/kafka-768x1008.jpeg 768w, https://static.digihunch.com/wp-content/uploads/2023/01/kafka.jpeg 1036w" sizes="auto, (max-width: 207px) 100vw, 207px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt; &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/07/nfs-network-file-system-and-rpc-remote-procedure-call/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;How RPC and NFS work&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/07/overview-of-virtualization/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Virtualization 1 of 4 – Hypervisor&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>How RPC and NFS work</title><link>https://static.digihunch.com/2020/07/nfs-network-file-system-and-rpc-remote-procedure-call/</link><pubDate>Wed, 15 Jul 2020 10:45:00 -0400</pubDate><guid>https://static.digihunch.com/2020/07/nfs-network-file-system-and-rpc-remote-procedure-call/</guid><description>&lt;p class="wp-block-paragraph"&gt;I touched on NFS in several previous postings, and here is a deeper dive of this particular protocol. NFS is built on top of Remote Procedure Call (RPC) and therefore it is important to understand RPC first. In fact NFS is one of the most prominent user of RPC and the best example for learning RPC.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;RPC overview&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;According to &lt;a href="https://en.wikipedia.org/wiki/Remote_procedure_call"&gt;Wikipedia&lt;/a&gt;, an RPC is when a computer program causes a procedure to execute in a different address space (commonly on another computer on a shared network), which is coded as if it were a normal (local) procedure call, without the programmer explicitly coding the details for the remote interaction. That is, the programmer writes essentially the same code whether the subroutine is local to the executing program, or remote. This is a form of client–server interaction (caller is client, executor is server), typically implemented via a request–response message-passing system. In the object-oriented programming paradigm, RPCs are represented by remote method invocation (RMI), such as Java RMI API.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;RPCs are a form of inter-process communication (IPC), in that other processes have a different address spaces: if on the same host machine, they have distinct virtual address spaces, even though the physical address space is the same; while if they are on different hosts, the physical address space is different. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;RPC is a&amp;nbsp;&lt;a href="https://en.wikipedia.org/wiki/Request%E2%80%93response"&gt;request–response&lt;/a&gt;&amp;nbsp;protocol, and therefore synchronous. An RPC is initiated by the&amp;nbsp;&lt;em&gt;client&lt;/em&gt;, which sends a request message to a known remote&amp;nbsp;&lt;em&gt;server&lt;/em&gt;&amp;nbsp;to execute a specified procedure with supplied parameters. The remote server sends a response to the client, and the application continues its process. While the server is processing the call, the client is blocked (it waits until the server has finished processing before resuming execution), unless the client sends an asynchronous request to the server. There are many variations and subtleties in various implementations, resulting in a variety of different (incompatible) RPC protocols.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="694" height="475" src="https://static.digihunch.com/wp-content/uploads/2020/07/image-1.png" alt="" class="wp-image-1161"/&gt;&lt;/figure&gt;&#10;&lt;h3 class="wp-block-heading"&gt;NFS overview&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;NFS is defined as a set of RPCs, including their arguments, results and effects. RPC makes NFS protocol transparent. RPC is also stateless so the server does not keep the state of RPCs once the request has been served. Each RPC contains the necessary information to complete the call. In the event of server failure, client will need to resubmit requests. &lt;a href="https://en.wikipedia.org/wiki/Network_File_System"&gt;NFS&lt;/a&gt; has several versions, with v3 and v4 most popular. We will focus on v3 in this posting and brief on v4.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Portmap&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;RPC makes a remote call appears to client application as a local call, with the help of &lt;a href="https://en.wikipedia.org/wiki/Portmap"&gt;portmap&lt;/a&gt;. The utility for portmap is rpcbind. In RedHat/CentOS 5 or prior, it was even simply called portmap but they are essentially the same service for RPC port mapper. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The rpcbind service is required on both NFS client and NFS server. On the client, it talks to client application, as well as its counterpart on the server. Its main function is query its counterpart on the server, providing a RPC program number, and expects a port number in return. On the server, the rpcbind utility listens at port 111, waiting for request with RPC program number(service), and return the TCP or UDP port number on which the requested service is hosted. RPC program number is reserved numeric indicator of services as outlined in &lt;a href="https://www.iana.org/assignments/rpc-program-numbers/rpc-program-numbers.xhtml"&gt;RFC5531&lt;/a&gt;. For example, 100005 for mountd, 100021 for nlockmgr, and 100003 for nfs. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The port that rpcbind service itself listens on is always at port 111, which is known to both client and server. This is also referred to as portmapper daemon. Other than this fixed port, each NFS-related service (with their respect reserved program number) may be hosted on different ports on the server. The client rpcbind service must first look up for the port for the requested program number, then it directs the client to initiate connection to the specified port for the specific service. &lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://docs.oracle.com/cd/E37838_01/html/E61058/figures/S9_portmap_seq.jpg" alt="image:Graphic illustrates portmap sequence for TCP/IP only"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With the following command rpcinfo command you may look up the program to port number mapping on destination server isilon.company.com&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;# rpcinfo -p isilon.company.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The following command is commonly used for displaying mountpoint and troubleshooting mount. Under the hood it is using the information from rpcinfo.&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;showmount -e isilon.dcb.digitalhunch.com&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;On the NFS server side, rpcbind service must start before nfs service start. Otherwise nfs service cannot register ports to rpcbind. If you restart rpcbind, every service that had registered to rpcbind must restart to register themselves again. By default, NFS server can dynamically assign a port for mountd, nlockmgr within a port range. &lt;a href="https://www.systutorials.com/fixing-ports-used-by-nfs-server/"&gt;This&lt;/a&gt; makes firewall setting a pain. These dynamically assigned port can be fixed via configuration files. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;File handle&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;NFS uses &lt;a href="https://www.ibm.com/support/knowledgecenter/SSLTBW_2.1.0/com.ibm.zos.v2r1.bpxb500/bpx1fr_NFS_file_handles.htm"&gt;file handles&lt;/a&gt; (or fhandle) to represent files. It is a better mechanism to reference a file object than pathname for three reasons: 1. file handle has fixed length (32bytes); 2. If the file is renamed, the file handle reference remain the same; 3. If a file is deleted, and then a new file is created with the same path, a new file handle will be created. A file handle has three parts:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;volume ID: to identify the mounted file system&lt;/li&gt;&lt;li&gt;inode #: to identify the file within the mounted file system&lt;/li&gt;&lt;li&gt;&lt;a href="https://utcc.utoronto.ca/~cks/space/blog/unix/NFSFilehandleInternals"&gt;generation #&lt;/a&gt;: to detect when file handle refers to an older version of inode. Traditional Unix filesystems may reuse inode and thus NFS client could mistakenly use an old file handle and access a new file.&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The file handle information is only meaningful to the server. New file handles are returned to client by certain procedures, such as LOOKUP, CREATE, and MKDIR. The file handle for the root of the file system, is obtained by the client when it mounts the file system, as permission allows.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Permission and Locking&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When accessing a file on server, the client passes uid/gid info in RPCs, and the server performs permission checks as if the user was performing the operation locally. So users and groups are represented as integers. There are two security problems:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&lt;li&gt;The mapping from uid/gid to user must be the same on all clients. This is not practical in large deployment, although can be solved via Network Information Service (NIS);&lt;/li&gt;&lt;li&gt;Whether the root user on the client has root access to files on the server, is a server policy configuration. This can be addressed by enabling &amp;#8220;root squashing&amp;#8221; on server, so that client&amp;#8217;s uid 0 (root) is mapped to 65534 (nobody).&lt;/li&gt;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Unix has &lt;a href="https://gavv.github.io/articles/file-locks/"&gt;two locking mechanisms&lt;/a&gt; (fcntl and flock). NFS protocol supports fcntl but not flock. The flock function is managed by a separate service (nfslock) to allow NFS to lock files. The &lt;a href="https://www.thegeekdiary.com/linux-os-service-nfslock/"&gt;nfslock&lt;/a&gt; daemon provides the ability to lock regions of NFS files. NFS service itself is still completely stateless with locking managed separately. This is changed in NFSv4.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Procedures used in NFS service&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;NFS service defines a &lt;a href="https://docs.oracle.com/cd/E19620-01/805-4448/z4000027624/index.html"&gt;list of procedures&lt;/a&gt;. Here is a list with brief summary of activities. The bottom five RPCs are introduced in v3.&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Procedure&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Activity&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GETATTR(fh)&lt;/td&gt;&lt;td&gt;Returns the attributes of a file, similar to stat syscall.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SETATTR(fh, attr)&lt;/td&gt;&lt;td&gt;Sets the attributes of a file (mode, uid, gid, size, atime, mtime); setting the size to 0 truncates the file&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;STATFS(fh)&lt;/td&gt;&lt;td&gt;Returns the status of a filesystem, such as block size, number of free blocks. e.g. df command.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LOOKUP (dirfh, name)&lt;/td&gt;&lt;td&gt;Returns fhandle and attributes for the named file in the directory specified by dirfh&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;READ (fh, offset, count)&lt;/td&gt;&lt;td&gt;Reads from a file, with offset and count specified. In v2, the length is up to 8192 bytes; v3 support more.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;WRITE (fh, offset, count, data)&lt;/td&gt;&lt;td&gt;Writes to a file, with offset and count specified, as well as a separate field called data. Returns the new attributes of the file after the write.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CREATE (dirfh, name, attr)&lt;/td&gt;&lt;td&gt;Creates a file with the name, in directory, returns new fhandle and attributes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;REMOVE (dirfh, name)&lt;/td&gt;&lt;td&gt;Deletes the named file in from directory dirfh and returns status.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;RENAME (dirfh, name, tofh, toname)&lt;/td&gt;&lt;td&gt;Renames name in directory dirfh, to toname in directory tofh.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;LINK (dirfh, name, tofh, toname)&lt;/td&gt;&lt;td&gt;Creates a hard link toname, in directory tofh, that points to name, indirectory dirfh.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;SYMLINK (dirfh, name, string)&lt;/td&gt;&lt;td&gt;Creates a symbolic link name, in the directory dirfh, with value string.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;READLINK (fh)&lt;/td&gt;&lt;td&gt;Reads a symbolic link and get file name of the target.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MKDIR (dirfh, name, attr)&lt;/td&gt;&lt;td&gt;Creates a directory name in the directory dirfh, and returns the new fh and attributes.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;RMDIR(dirfh, name)&lt;/td&gt;&lt;td&gt;Removes a directory with the name, from parent directory dirfh.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;READDIR (dirfh, cookie, count)&lt;/td&gt;&lt;td&gt;Reads a directory and returns up to count bytes of directory entries from the directory dirfh. The cookie is used in subsequent readdir calls to start reading at a specific entry in the directory. Cookie of zero get the server to start with the first entry in the directory.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;NULL&lt;/td&gt;&lt;td&gt;No activity. Used for testing only.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ACCESS&lt;/td&gt;&lt;td&gt;Helps with client caching.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MKNOD&lt;/td&gt;&lt;td&gt;Makes a device special file.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FSINFO&lt;/td&gt;&lt;td&gt;Returns information about the server&amp;#8217;s capabilities. &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;READDIRPLUS&lt;/td&gt;&lt;td&gt;Returns both file handle and attributes to eliminate LOOKUP calls when scanning a directory&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;COMMIT&lt;/td&gt;&lt;td&gt;In NFSv3, the server can reply to WRITE RPCs immediately without syncing to disk. When client wants to ensure that the data is on stable storage, it sends a COMMIT RPC. This is used in asynchronous writes for better performance, which is an option negotiated at mount time.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The addition of COMMIT procedure in v3 offers the option to improve write performance in place of synchronous write. However, asynchronous write requires more coordination to ensure data integrity during transmission, in the event of server crash. NFSv3 uses write verifier for this purpose. A write verifier is an 8-bye value that the server must change if it crashes. &lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;After an asynchronous write, the reply from WRITE RPC includes a write verifier, the client must keep it for later use;&lt;/li&gt;&lt;li&gt;The client then sends a COMMIT RPC and the reply contains another write verifier;&lt;/li&gt;&lt;li&gt;The client compares the verifiers from the two returns for crash detection. If the verifiers don&amp;#8217;t match, the client must rewrite all uncommitted data.&lt;/li&gt;&lt;li&gt;The client must keep all uncommitted data in case of a server crash.&lt;/li&gt;&lt;/ul&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Additional daemon processes&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In addition to the three essential services, (nfs, rpcbind and nfslock), there are several auxiliary processes that facilitates NFS services. Their functions are listed &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/storage_administration_guide/ch-nfs"&gt;here&lt;/a&gt;:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Process&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;rpc.mountd&lt;/td&gt;&lt;td&gt;Used by NFS server to process MOUNT requests from NFSv3 client. It checks that the requested NFS share is currently exported by the NFS server, and that the client is allowed to access it. If the mount request is allowed, the rpc.mountd server replies with a Success status and provides the File-Handle for this NFS share back to the NFS client.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;rpc.nfsd&lt;/td&gt;&lt;td&gt;Allows explicit NFS versions and protocols the server advertises to be defined. It works with the Linux kernel to meet the dynamic demands of NFS clients, such as providing server threads each time an NFS client connects. This process corresponds to the nfs service.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;rpc.lockd&lt;/td&gt;&lt;td&gt;A kernel thread which runs on both clients and servers. It implements the Network Lock Manager (NLM) protocol, which allows NFSv3 clients to lock files on the server, using procedures such as NLM_NULL, NLM_TEST, NLM_LOCK, NLM_GRANTED, NLM_UNLOCK, NLM_FREE. The service is started automatically whenever the NFS server is run and whenever an NFS file system is mounted.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;rpc.statd&lt;/td&gt;&lt;td&gt;This process implements the Network Status Monitor (NSM) RPC protocol, which notifies NFS clients when an NFS server is restarted without being gracefully brought down. rpc.statd is started automatically by the nfslock service, and does not require user configuration. This is not used with NFSv4.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;rpc.rquotad&lt;/td&gt;&lt;td&gt;This process provides user quota information for remote users. rpc.rquotad is started automatically by the nfs service and does not require user configuration.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;rpc.idmapd&lt;/td&gt;&lt;td&gt;provides NFSv4 client and server upcalls, which map between on-the-wire NFSv4 names (strings in the form of user@domain) and local UIDs and GIDs. For idmapd to function with NFSv4, the /etc/idmapd.conf file must be configured. At a minimum, the &amp;#8220;Domain&amp;#8221; parameter should be specified, which defines the NFSv4 mapping domain. If the NFSv4 mapping domain is the same as the DNS domain name, this parameter can be skipped. The client and server must agree on the NFSv4 mapping domain for ID mapping to function properly.&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;h3 class="wp-block-heading"&gt;NFSv4&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Even NFSv4 was introduced in 20 years ago, it improves access and performance of NFS on the Internet. It should be the default option for any new deployment.&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;NFSv4 is TCP only protocol and it is stateful. &lt;/li&gt;&lt;li&gt;NFSv4 combines mount and lock protocols into NFS so only one port is being used. &lt;/li&gt;&lt;li&gt;Users and groups are identified with strings (user@domain, or group@domain where domain represents a registered DNS domain or sub-domain), instead of integers. The access control policies are compatible with both Unix and Windows.&lt;/li&gt;&lt;li&gt;NFSv4 mandates strong RPC security built on cryptography, with negotiation at the time of mount&lt;/li&gt;&lt;li&gt;NFSv4 adopted a framework for authentication, integrity and privacy at RPC level&lt;/li&gt;&lt;li&gt;Introduced new RPC COMPOUND, which allows for several operations in one go. At the server, operations are evaluated in order, and each has a return value.&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;NFSv4.1 was release in 2010, and 4.2 in 2016. Both AWS EFS and Azure File storage supports 4.1.&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/07/emc-productlines/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;EMC Isilon storage product&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/07/zookeeper-and-kafka-overview/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Kafka high-level Overview&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Performance Analysis</title><link>https://static.digihunch.com/2020/06/performance-analysis-tools/</link><pubDate>Fri, 19 Jun 2020 16:47:01 -0400</pubDate><guid>https://static.digihunch.com/2020/06/performance-analysis-tools/</guid><description>&lt;h3 class="wp-block-heading" id="h-overview"&gt;Overview&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In 2015, Brendan Gregg posted two great articles&lt;a href="https://netflixtechblog.com/linux-performance-analysis-in-60-000-milliseconds-accc10403c55"&gt; &lt;/a&gt;on Netflix blog: &lt;a href="https://netflixtechblog.com/linux-performance-analysis-in-60-000-milliseconds-accc10403c55"&gt;Linux Performance Analysis in 60 seconds&lt;/a&gt;, and &lt;a href="https://netflixtechblog.com/netflix-at-velocity-2015-linux-performance-tools-51964ddb81cf"&gt;Linux Perfomrance Tools&lt;/a&gt;. They have great value when I was in a urgency to spot performance issues. The articles cover the essential tools for performance troubleshooting, including:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Check out load averages: w or uptime&lt;/li&gt;&#10;&lt;li&gt;Print kernel ring buffer: dmesg -T&lt;/li&gt;&#10;&lt;li&gt;Virtual memory status: vmstat 1&lt;/li&gt;&#10;&lt;li&gt;Multiple processor staticstics: mpstat -P ALL 1&lt;/li&gt;&#10;&lt;li&gt;Task status: pidstat 1&lt;/li&gt;&#10;&lt;li&gt;CPU and I/O status: iostat -xz 1&lt;/li&gt;&#10;&lt;li&gt;Free memory check: free -m&lt;/li&gt;&#10;&lt;li&gt;Network Activity record: sar -n DEV 1&lt;/li&gt;&#10;&lt;li&gt;TCP activity record: sar -n TCP,ETCP 1&lt;/li&gt;&#10;&lt;li&gt;Display processes: top&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We will dive into each of them in the next section.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-basic-troubleshooting"&gt;Basic Troubleshooting&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The command w is equivalent of uptime (which shows uptime since boot) and who (which shows logged-in users). It also displays load average for the last 1 minute, 5 minutes and 15 minutes. The number of load average reflects the overall system load (CPU + disks), and it is further discussed in this &lt;a href="http://www.brendangregg.com/blog/2017-08-08/linux-load-averages.html"&gt;post&lt;/a&gt; with a simple take away:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;If the averages are 0.0, then your system is idle.&lt;/li&gt;&#10;&lt;li&gt;If the 1 minute average is higher than the 5 or 15 minute averages, then load is increasing.&lt;/li&gt;&#10;&lt;li&gt;If the 1 minute average is lower than the 5 or 15 minute averages, then load is decreasing.&lt;/li&gt;&#10;&lt;li&gt;If they are higher than your CPU count, then you might have a performance problem (it depends).&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When Linux load averages increase, you know you have higher demand for resources (CPUs, disks, and some locks), but you aren&amp;#8217;t sure which. You will need to switch to other metrics. Brendan recommend don&amp;#8217;t spend more than 5 seconds on these numbers.&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;dhunch@c7v-ghintapp01 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ w&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 12:14:10 up &lt;span style="color:#ae81ff"&gt;46&lt;/span&gt; days, 16:41, &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; users, load average: 2.69, 2.44, 2.29&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dhunch pts/0 w6v-ghas01 24Jun20 3days 0.36s 0.30s ssh c7v-bastion&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dhunch pts/1 202.95.88.111 12:02 2.00s 0.00s 0.00s w&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;dhunch pts/4 w6v-ghas01 17Jun20 15days 0.15s 0.07s view readme.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Before moving to more insightful metrics, it is also worth a quick look into the kernel ring buffer with dmesg command (dmesg -T | less +G). This will allow us to capture obvious issues such as oom-killer or TCP request dropping.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The vmstat tool reports the statistics of &lt;strong&gt;virtual memory&lt;/strong&gt;. Servers have a fixed amount of physical memory, but they can run a set of applications that use a much larger amount of virtual memory. Application tend to reserve more memory than they need, and they usually operate on only a subset of their memory. In both cases, the operating system can keep the unused parts of memory on disk, and page it into physical memory only if it is needed. For the most part, this kind of memory management works well. But it doesn&amp;#8217;t always with Java applications due to Java heap. Once a system start swapping &amp;#8211; moving pages of data from main memory to disk, and vice versa, the performance tend to be bad. Systems must be configured so that swapping never occurs.&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;dhunch@c7v-ghintapp01 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ vmstat &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; r b swpd free buff cache si so bi bo in cs us sy id wa st&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;239360&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;385928&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;36734692&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;200&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;93&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;239360&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;387732&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;36734704&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;43&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8017&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8524&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;85&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;239360&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;387608&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;36734904&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;57&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6768&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7680&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;86&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;239360&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;389008&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;36734904&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;44&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6366&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7300&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;86&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;239360&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;421728&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;36700144&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8141&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7957&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;86&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;239360&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;421984&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;36702048&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;467&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8994&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;8362&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;85&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The tool prints key server statistics each line, with the first line showing the average since boot. Here lists the explanation of some columns:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;r&lt;/strong&gt;: number of processes running on CPU and waiting for a turn. This provides a better signal than load averages for determining CPU saturation, as it does not include I/O. To interpret: an “r” value greater than the CPU count is saturation.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;swpd&lt;/strong&gt;: the amount of virtual memory used. This number should align with the used column for Swap row from free command.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;buff, cache&lt;/strong&gt;: buffer and cache. They should align with the buff/cache column form Mem row from free command.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;free&lt;/strong&gt;: free memory in kilobytes. This number should align with the free column for Mem row from free command. &lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;si, so&lt;/strong&gt;: swap-ins and swap-outs. As mentioned, if these are non-zero, you&amp;#8217;re out of memory.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;bi, bo&lt;/strong&gt;: blocks received from and sent to a blcok device (# of block per second)&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;in, cs&lt;/strong&gt;: number of &lt;a href="https://en.wikipedia.org/wiki/Interrupt"&gt;interrupt&lt;/a&gt;, and &lt;a href="https://en.wikipedia.org/wiki/Context_switch"&gt;context switches&lt;/a&gt; per second.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;us, sy, id, wa, st&lt;/strong&gt;: user, system, idle, wait I/O and stolen times. These are breakdowns of CPU time, on average across all CPUs. They should add up to 100% (or close). stolen time is amount of CPU time needed by a guest virtual machine that is not provided by the host. IO wait time is the CPU time waiting for I/O activity. Idle time could be several things: the process may be waiting for something (e.g. a response from database); the process may be blocked by a thread lock; or the process simply has nothing to do. user and system times are CPU times spent on user tasks and kernel tasks, respectively.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Out of these columns, watch for columns r, free, buff, cache, us, sy, id and wa at minimum. The combination of us and sy confirms if CPUs are busy. A constant degree of wa points to a disk bottleneck with too much time spent on pending disk I/O. The sy (kernel time) is necessary for I/O processing but sy stays high (e.g. constantly over 20%), it becomes interesting. Perhaps the kernel is processing I/O inefficiently.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For further per-CPU stats, use mpstat command (-P ALL), to prind CPU time breakdowns per CPU and check for imbalance. A single host CPU can be evidence of a single-threaded application. Here is an example output from a system of 16 CPU cores.&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;dhunch@c7v-ghintapp01 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ mpstat -P ALL &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Linux 3.10.0-1062.12.1.el7.x86_64 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;c7v-ghintapp01.digihunch.com&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 08/01/20 _x86_64_ &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; CPU&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:23 CPU %usr %nice %sys %iowait %irq %soft %steal %guest %gnice %idle&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:24 all 13.77 0.00 0.19 0.00 0.00 0.00 0.00 0.00 0.00 86.05&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:24 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 2.02 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 97.98&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:24 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 2.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:24 &lt;span style="color:#ae81ff"&gt;2&lt;/span&gt; 2.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:24 &lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; 98.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 2.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:24 &lt;span style="color:#ae81ff"&gt;4&lt;/span&gt; 2.02 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 97.98&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:24 &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; 2.02 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 97.98&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:24 &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt; 2.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:24 &lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; 2.94 0.00 0.98 0.00 0.00 0.00 0.00 0.00 0.00 96.08&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:24 &lt;span style="color:#ae81ff"&gt;8&lt;/span&gt; 2.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:24 &lt;span style="color:#ae81ff"&gt;9&lt;/span&gt; 2.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:24 &lt;span style="color:#ae81ff"&gt;10&lt;/span&gt; 97.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 3.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:24 &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; 0.99 0.00 0.99 0.00 0.00 0.00 0.00 0.00 0.00 98.02&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:24 &lt;span style="color:#ae81ff"&gt;12&lt;/span&gt; 2.02 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 97.98&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:24 &lt;span style="color:#ae81ff"&gt;13&lt;/span&gt; 1.98 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.02&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:24 &lt;span style="color:#ae81ff"&gt;14&lt;/span&gt; 2.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 98.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;13:47:24 &lt;span style="color:#ae81ff"&gt;15&lt;/span&gt; 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 100.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;For a per process summary of CPU consumption, use pidstat command. It can be thought of a periodical snapshot of top command, allowing you to watch for patterns. The %CPU column is the total across all CPUs so 5 CPUs have a maximum value of 500.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If vmstate indicates some I/O issue, iostat tool can help us understand block devices, on both the workload applied and the resulting performance. Key columns are:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;r/s, w/s, rkB/s, wkB/s&lt;/strong&gt;: delivered reads, writes, read Kbytes, and write Kbytes per second to the device. Use these for workload characterization. A performance problem may simply be due to an excessive load applied.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;await&lt;/strong&gt;: the average wait time for I/O in milliseconds. This is the time that the application suffers, as it includes both time queued and time being serviced. Larger than expected average times can be an indicator of device saturation, or malfunction.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;avgqu-sz&lt;/strong&gt;: the average number of requests issued to device. Values greater than 1 can be evidence of saturation (although devices can typically operate on requests in parallel, especially virtual devices which front multiple back-end disks.)&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;%util&lt;/strong&gt;: device utilization. This is really a busy percent, showing the time each second that the device was doing work. Values greater than 60% typically lead to poor performance (which should be seen in await), although it depends on the device. Values close to 100% usually indicate saturation.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I/O problem may either be inefficiencies in application that issues I/O request, or slowing disk unable to keep up with I/O requests. We review two examples here to illustrate each situation. The first output is as follows:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% iostat -xm &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;avg-cpu: %user %nice %system %iowait %steal %idle&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 23.45 0.00 37.89 0.10 0.00 38.56&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sda 0.00 11.60 0.60 24.20 0.02 0.14 13.35 0.15 6.06 5.33 6.08 0.42 1.04&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In the first example, the disk stat loosk up at first glance. The w_await (time to service I/O write) is fairly low at 6.08ms. However, the system is spending 37.89% of its time in the kernel. If all that system time is from the application, it suggest something inefficient is happening. The fact that the system is doing 24.2 writes per second is another clue: that is alot when writing only 0.14 MB per second (MBps). I/O has become a bottleneck, and the next step would be to look into how the application is performing its writes.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The second example output is as follows:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;% iostat -xm &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;avg-cpu: %user %nice %system %iowait %steal %idle&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 35.05 0.00 7.85 47.89 0.00 9.20&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sda 0.00 0.20 1.00 163.40 0.00 81.09 1010.19 142.74 866.47 97.60 871.17 6.08 100.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In this example, it tells us that processes are spending 47.89% of their time in iowait, and the data to complete the I/O (w_await) is 871ms, the queue size is large, and the disk is writing at 81MB per second. This all points to disk I/O as a problem and that the amount of I/O in the application (or elsewhere in the system) must be reduced.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Bear in mind that poor performing disk I/O isn&amp;#8217;t necessarily an application issue. Many techniques are typically used to perform I/O asynchronously, so that the application doesn&amp;#8217;t block and suffer the latency directly (e.g. read-ahead for reads, and buffering for writes, also refer to &amp;#8220;&lt;a href="https://robertovitillo.com/why-you-should-measure-tail-latencies/"&gt;tail latency&lt;/a&gt;&amp;#8220;). &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Note that the acceptable utilization metric depends on the configuration of block device. If the storage is a logical disk device fronting many back-end disks (e.g. RAID 0), then 100% utilization may just mean that some I/O is being processed 100% of the time, however, the back-end disks may be far from being saturated, and may even be able to handle more work.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The free command gives the breakdown of memory usage. The right two columns are:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;buffers&lt;/strong&gt;: for the buffer cache, used for block device I/O.&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;cached&lt;/strong&gt;: for the page cache, used by file systems.&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We just want to check that these aren&amp;#8217;t near-zero in size, which can lead to higher disk I/O (confirm using iostat), and worse performance. Linux uses free memory for the caches, but can reclaim it quickly if applications need it. So in a way the cached memory should be included in the free memory column. In this case, it&amp;#8217;s included in the available column. This &lt;a href="https://www.linuxatemyram.com/"&gt;website &lt;/a&gt;has further details.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To check interface stat, nicstat is a great tool but it isn&amp;#8217;t available by default in Linux. Instead we can run sar (-n DEV) to retrieve stats. &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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;dhunch@c7v-ghintapp01 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ sar -n DEV &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Linux 3.10.0-1062.12.1.el7.x86_64 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;c7v-ghintapp01.digihunch.com&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 08/01/20 _x86_64_ &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; CPU&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16:51:25 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16:51:26 eth0 3089.00 934.00 3815.33 834.61 0.00 0.00 0.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16:51:26 lo 464.00 464.00 2289.07 2289.07 0.00 0.00 0.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16:51:26 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16:51:27 eth0 956.00 586.00 826.66 211.34 0.00 0.00 0.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16:51:27 lo 213.00 213.00 196.00 196.00 0.00 0.00 0.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16:51:27 IFACE rxpck/s txpck/s rxkB/s txkB/s rxcmp/s txcmp/s rxmcst/s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16:51:28 eth0 349.00 181.00 52.32 147.19 0.00 0.00 0.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16:51:28 lo 244.00 244.00 81.13 81.13 0.00 0.00 0.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Here rxkB/s/s and txkB/s represents receive and transmission throughput, as a measure of workload. If they reach the limit then the interface is the bottleneck.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On top of interface is the TCP layer, which can be monitored with sar again (-n ECP, ETCP). The key metrics are:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;active/s&lt;/strong&gt;: number of locally-initiated (e.g. via connect()) TCP connections per second&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;passive/s&lt;/strong&gt;: number of remotely-initiated (e.g. via accept()) TCP connections per second&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;retrans/s&lt;/strong&gt;: number of TCP retransmits per second&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The active and passive counts are often useful as a rough measure of server load. It might help to think of active as outbound, and passive as inbound, but this isn&amp;#8217;t strictly true (e.g. consider a localhost to localhost connection). Retransmits are a sign of network or server issue; it may be an unreliable network (e.g. public Internet), or it may be due to a server being overloaded and dropping packets.&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;dhunch@c7v-ghintapp01 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;$ sar -n TCP,ETCP &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Linux 3.10.0-1062.12.1.el7.x86_64 &lt;span style="color:#f92672"&gt;(&lt;/span&gt;c7v-ghintapp01.digihunch.com&lt;span style="color:#f92672"&gt;)&lt;/span&gt; 08/01/20 _x86_64_ &lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt; CPU&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16:52:29 active/s passive/s iseg/s oseg/s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16:52:30 0.00 1.00 28.00 35.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16:52:29 atmptf/s estres/s retrans/s isegerr/s orsts/s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16:52:30 0.00 0.00 0.00 0.00 0.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16:52:30 active/s passive/s iseg/s oseg/s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16:52:31 8.00 8.00 200.00 317.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16:52:30 atmptf/s estres/s retrans/s isegerr/s orsts/s&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;16:52:31 0.00 1.00 1.00 0.00 3.00&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Last but not least is our favourite command top, which includes many of the metrics covered in previous tools. The downside to top is it is harder to see patterns over time, which may be more clear in tools like vmstat and pidstat, both of which produce rolling output.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Several tools introduced here involves sar, which is a great monitoring tool on its own that we need to be familiar with.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-system-activity-report-sar"&gt;System Activity Report (SAR)&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Further to the basic tools, the sar command is very helpful as it stores historical stat every 10 minutes. Sar keeps 18 types of reports, all stored in /var/log/sa/. When viewing the report file, you may pipe the result to less command so it only prints header once. For example, if you would like to print CPU report for the 2nd of the month:&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;# sar -u -f /var/log/sa/sar02 | less&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;If you check NFS client statistics for the 31st&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; # sar -n NFS -f /var/log/sa/sar31&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;If you need to check network server statistics for today&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;# sar -n NFS -f /var/log/sa/sar31&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Below are all types of reports:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;-u CPU utilization&lt;/li&gt;&#10;&lt;li&gt;-w task creation and system switching activity&lt;/li&gt;&#10;&lt;li&gt;-W swapping statistics&lt;/li&gt;&#10;&lt;li&gt;-B report paging&lt;/li&gt;&#10;&lt;li&gt;-b report I/O and transfer rate statistics&lt;/li&gt;&#10;&lt;li&gt;-R report memory statistics&lt;/li&gt;&#10;&lt;li&gt;-r memory utilization&lt;/li&gt;&#10;&lt;li&gt;-S swap space utilization&lt;/li&gt;&#10;&lt;li&gt;-H huge pages utilization statistics&lt;/li&gt;&#10;&lt;li&gt;-v inode&lt;/li&gt;&#10;&lt;li&gt;-q queue length and load average&lt;/li&gt;&#10;&lt;li&gt;-y TTY device activity&lt;/li&gt;&#10;&lt;li&gt;-d activity for each block device&lt;/li&gt;&#10;&lt;li&gt;-n network statistics, DEV (per interface)&lt;/li&gt;&#10;&lt;li&gt;-n network statistics, EDEV (error per interface)&lt;/li&gt;&#10;&lt;li&gt;-n network statistics, NFS (NFS client)&lt;/li&gt;&#10;&lt;li&gt;-n network statistics, NFSD (NFS server)&lt;/li&gt;&#10;&lt;li&gt;-n network statistics, SOCK (socket usage)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 class="wp-block-heading" id="h-berkeley-packet-filter-bpf-compiler-collection-bcc-tools"&gt;Berkeley Packet Filter (BPF) Compiler Collection (bcc) tools&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For advanced, low-level performance troubleshooting, the BCC tools provide a suite of tools. Here we only cover the installation of it.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In CentOS, install bcc-tools package with yum. When you try to run a command, such as cachestat, if you come across this error:&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;-bash: cachestat: command not found&#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 will need to add its path to default:&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;export PATH=$PATH:/usr/share/bcc/tools&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Now if you run into this error:&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;chdir(/lib/modules/3.10.0-1062.12.1.el7.x86_64/build): No such file or directory&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Traceback (most recent call last):&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The file listed is a symbolic link, and if it is missing, you just need to install kernel-headers that matches the kernel version:&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;yum install kernel-headers&#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 may use tools in /usr/share/bcc/tools. For example, cachestat help you display page cache hit ratio; gethostlatency shows DNS resolution latency; tcpconnect prints out active tcp connections (made via connect system call):&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;[root@dhunch ~]# /usr/share/bcc/tools/tcpconnect -t -P 8080 | gawk &amp;#39;{ print strftime(&amp;#34;%F %T  &amp;#34;), $0 }&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-06-13 00:16:57   TIME(s)  PID    COMM         IP SADDR            DADDR            DPORT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-06-13 02:16:57   0.000    15241  QNetworkAcce 4  10.100.22.21    10.101.84.10    8080&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-06-13 02:16:57   0.064    15241  QNetworkAcce 4  10.100.22.21    10.101.84.10    8080&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;2020-06-13 02:16:57   0.438    15241  QNetworkAcce 4  10.100.22.21    10.101.84.10    8080&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The command above outputs a&amp;nbsp;time and pid stamped log line every time&amp;nbsp;a TCP connection is made to port 8080; tcpaccept traces passive tcp connections (via accept system call). These tools are not as intrusive as tcpdump.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;It is beyond the purpose of this article to get into details of each tool in the BFP suite. The tools are covered in detail in books &amp;#8220;&lt;a href="https://amzn.to/3fEWNkq"&gt;BPF Performance Tools&lt;/a&gt;&amp;#8221; and &amp;#8220;Linux Observability with BPF&amp;#8221;.&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/06/network-analyzer-capture-filter-and-display-filter/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Capture filter and Display filter in Network Analyzer&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/06/iterate-through-cassandra-table-with-datastax-python-driver/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;DataStax Python Driver&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Setup WSL2 (and Docker) on Windows 10</title><link>https://static.digihunch.com/2020/06/wsl2-environment-on-windows-10/</link><pubDate>Tue, 02 Jun 2020 22:01:00 -0400</pubDate><guid>https://static.digihunch.com/2020/06/wsl2-environment-on-windows-10/</guid><description>&lt;p class="wp-block-paragraph"&gt;This is not for Linux snobs, but rather for those who are stuck with a Windows work laptop, have to deal with Linux on a daily basis, and are not a fan of PuTTY. This posting provides the steps to setup Windows 10 so you get a work environment closer to a Linux one. The environment to begin with should be Windows 10 version 2004 and above in order to use WSL2. &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/compare-versions"&gt;Here&amp;#8217;s &lt;/a&gt;the comparison between WSL and WSL2. This &lt;a href="https://www.youtube.com/watch?v=lwhMThePdIo"&gt;presentation &lt;/a&gt;is a great deep dive into how WSL2 works. The architecture diagram below is from that presentation. Note that WSL2 operates on a &amp;#8220;true&amp;#8221; Linux Kernel, therefore giving WSL2 the ability to run Docker.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://4.bp.blogspot.com/-e_FaEsP7nH8/Xca4QMFtjQI/AAAAAAAAERA/r59YN5UCXlwdNsfPNy-sjjyTQ4o_dtbjACLcBGAsYHQ/s1600/wsl1-wsl2.png" alt=""/&gt;&lt;/figure&gt;&#10;&lt;h3 class="wp-block-heading" id="h-install-wsl2"&gt;Install WSL2&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;WSL2 was officially released in Windows 10 version 2004 (build 19041 or higher) and we will use Ubuntu 20.04 LTS. If you&amp;#8217;re upgraded from older version of Windows 10 you will need to upgrade. The steps are:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;Install Ubuntu 20.04 LTS from Microsoft Store, which requires Windows components &amp;#8220;Windows Subsystem for Linux&amp;#8221; and &amp;#8220;Virtual Machine Platform&amp;#8221;; or, if you already have an older version of Ubuntu such as 18.04, you will need to run a distribution upgrade with &amp;#8220;sudo apt-get dist-upgrade&amp;#8221;;&lt;/li&gt;&#10;&lt;li&gt;Upgrade Linux Virtual Machine from WSL to WSL2, following the official instruction &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10"&gt;here&lt;/a&gt;; Once completed, use this command to confirm the WSL version installed: wsl.exe &amp;#8211;list -v&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;div class="wp-block-image"&gt;&#10;&lt;figure class="aligncenter size-large is-resized"&gt;&lt;img loading="lazy" decoding="async" width="634" height="104" src="https://static.digihunch.com/wp-content/uploads/2020/06/image-1.png" alt="" class="wp-image-1056" style="width:317px;height:52px"/&gt;&lt;/figure&gt;&#10;&lt;/div&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There&amp;#8217;s also plenty of Youtube videos with step-by-step instruction on upgrading to WSL2 and its advantage over WSL. Once you&amp;#8217;re there, you will realize one problem: the command terminal for Ubuntu is ugly:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="2318" height="622" src="https://static.digihunch.com/wp-content/uploads/2020/06/image.png" alt="" class="wp-image-1055"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The colour looks awful and it does not support multi-tabs. If you want better palette, there are a number of options. Check out &lt;a href="https://github.com/Microsoft/Terminal/tree/master/src/tools/ColorTool"&gt;ColorTool&lt;/a&gt; project and &lt;a href="https://github.com/mbadolato/iTerm2-Color-Schemes"&gt;iTerms2 Colors&lt;/a&gt; project. The former gives you away to configure color scheme (from command prompt but takes effect in WSL as well) and the latter gives you rich choices of color schemes. My personal favourite is &amp;#8220;Banana Blueberry&amp;#8221;. The command to set color scheme is: &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;C:\ColorTool.exe -b &amp;#34;iTerm2-Color-Schemes-master\schemes\Banana Blueberry.itermcolors&amp;#34;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 class="wp-block-heading" id="h-windows-terminal"&gt;Windows Terminal&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For a better terminal, consider Windows Terminal from Microsoft Store. &lt;a href="https://github.com/microsoft/terminal"&gt;Windows terminal&lt;/a&gt; is an open-source project and still a little &lt;a href="https://github.com/microsoft/terminal/issues/4448"&gt;glitchy&lt;/a&gt; as of June 2020. However it is heading to the right direction. Once installed, you may customize it by clicking settings:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1066" height="412" src="https://static.digihunch.com/wp-content/uploads/2020/06/image-3.png" alt="" class="wp-image-1058"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;A json file will open and you may edit it for customization, for example, you can adjust each profile (e.g. PowerShell, Windows command or WSL); you can specify default profile and default open location. &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-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// This file was initially generated by Windows Terminal 1.0.1401.0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// It should still be usable in newer versions, but newer versions might have additional&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// settings, help text, or changes that you will not see unless you clear this file&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// and let us generate a new one for you.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// To view the default settings, hold &amp;#34;alt&amp;#34; while clicking on the &amp;#34;Settings&amp;#34; button.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// For documentation on these settings, see: https://aka.ms/terminal-documentation&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;{&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;$schema&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;https://aka.ms/terminal-profiles-schema&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;defaultProfile&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;{2c4de342-38b7-51cf-b940-2309a097f518}&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// You can add more global application settings here.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// To learn more about global settings, visit https://aka.ms/terminal-global-settings&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// If enabled, selections are automatically copied to your clipboard.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;copyOnSelect&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// If enabled, formatted data is also copied to your clipboard&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;copyFormatting&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// A profile specifies a command to execute paired with information about how it should look and feel.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Each one of them will appear in the &amp;#39;New Tab&amp;#39; dropdown,&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// and can be invoked from the commandline with `wt.exe -p xxx`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// To learn more about profiles, visit https://aka.ms/terminal-profile-settings&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;profiles&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;defaults&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Put settings here that you want to apply to all profiles.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;list&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;guid&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;{2c4de342-38b7-51cf-b940-2309a097f518}&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Ubuntu&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;source&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Windows.Terminal.Wsl&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;startingDirectory&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;//wsl$/Ubuntu/home/myuser/&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Make changes here to the powershell.exe profile.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;guid&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;{61c54bbd-c2c6-5271-96e7-009a87ff44bf}&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Windows PowerShell&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;commandline&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;powershell.exe&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Make changes here to the cmd.exe profile.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;guid&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;{0caa0dad-35be-5f56-a8ff-afceeeaa6101}&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Command Prompt&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;commandline&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;cmd.exe&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;guid&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;{b453ae62-4e3d-5e58-b989-0a998ec441b8}&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;true&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;name&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Azure Cloud Shell&amp;#34;&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;source&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;Windows.Terminal.Azure&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Add custom color schemes to this array.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// To learn more about color schemes, visit https://aka.ms/terminal-color-schemes&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;schemes&amp;#34;&lt;/span&gt;: &lt;span style="color:#f92672"&gt;[]&lt;/span&gt;,&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Add custom keybindings to this array.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// To unbind a key combination from your defaults.json, set the command to &amp;#34;unbound&amp;#34;.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// To learn more about keybindings, visit https://aka.ms/terminal-keybindings&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;keybindings&amp;#34;&lt;/span&gt;:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Copy and paste are bound to Ctrl+Shift+C and Ctrl+Shift+V in your defaults.json.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// These two lines additionally bind them to Ctrl+C and Ctrl+V.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// To learn more about selection, visit https://aka.ms/terminal-selection&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e6db74"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;: {&lt;span style="color:#e6db74"&gt;&amp;#34;action&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;copy&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;singleLine&amp;#34;&lt;/span&gt;: &lt;span style="color:#66d9ef"&gt;false&lt;/span&gt; }, &lt;span style="color:#e6db74"&gt;&amp;#34;keys&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;ctrl+c&amp;#34;&lt;/span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e6db74"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;paste&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;keys&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;ctrl+v&amp;#34;&lt;/span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Press Ctrl+Shift+F to open the search box&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e6db74"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;find&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;keys&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;ctrl+shift+f&amp;#34;&lt;/span&gt; },&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// Press Alt+Shift+D to open a new pane.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// - &amp;#34;split&amp;#34;: &amp;#34;auto&amp;#34; makes this pane open in the direction that provides the most surface area.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// - &amp;#34;splitMode&amp;#34;: &amp;#34;duplicate&amp;#34; makes the new pane use the focused pane&amp;#39;s profile.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;// To learn more about panes, visit https://aka.ms/terminal-panes&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; { &lt;span style="color:#e6db74"&gt;&amp;#34;command&amp;#34;&lt;/span&gt;: { &lt;span style="color:#e6db74"&gt;&amp;#34;action&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;splitPane&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;split&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;auto&amp;#34;&lt;/span&gt;, &lt;span style="color:#e6db74"&gt;&amp;#34;splitMode&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;duplicate&amp;#34;&lt;/span&gt; }, &lt;span style="color:#e6db74"&gt;&amp;#34;keys&amp;#34;&lt;/span&gt;: &lt;span style="color:#e6db74"&gt;&amp;#34;alt+shift+d&amp;#34;&lt;/span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;With these configuration, we have a quite comfortable Linux work environment on Windows.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-update-to-zsh-and-beautify-it"&gt;Update to Zsh and beautify it&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I&amp;#8217;m no so big a fan of zsh (for lack of default &lt;a href="https://superuser.com/questions/584249/using-wildcards-in-commands-with-zsh/740728"&gt;wildcard support&lt;/a&gt;) but I do like one of its themes. We can install zsh on WSL2 (assuming Ubuntu distribution). This is a good &lt;a href="https://blog.nillsf.com/index.php/2020/02/17/setting-up-wsl2-windows-terminal-and-oh-my-zsh/"&gt;instruction&lt;/a&gt;. I do like the theme name agnoster. However, the theme displays username at the beginning of the prompt, which takes a lot of screen real estate if your username is long. To remove it, the trick is to add a line in ~/.zshrc, as answered in &lt;a href="https://stackoverflow.com/questions/28491458/zsh-agnoster-theme-showing-machine-name/38295938#:~:text=You%20can%20set%20DEFAULT_USER%3D%22%5B,the%20%5Buser%20name%5D%20value.&amp;amp;text=This%20will%20negate%20the%20%22%24user%22%20!%3D"&gt;this&lt;/a&gt; thread. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-docker-runtime"&gt;Docker runtime&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There is a lot of fun to have in WSL2 on Windows 10. For example, you can configure Docker runtime on Windows according to &lt;a href="https://nickjanetakis.com/blog/a-linux-dev-environment-on-windows-with-wsl-2-docker-desktop-and-more"&gt;this post&lt;/a&gt;. However, you cannot route traffic to the container in the absence of docker0 bridge for Docker on WSL2, as indicated in the &lt;a href="https://docs.docker.com/desktop/windows/networking/#known-limitations-use-cases-and-workarounds"&gt;known limitations&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Update: Docker also brings a Kubernetes cluster named docker-desktop. This allows you configure Kubernetes cluster, or install &lt;a href="https://static.digihunch.com/2021/07/helm-configuration-management-for-kubernetes-resources/"&gt;Helm&lt;/a&gt; and Rancher (&lt;a href="https://rafalfaro.medium.com/how-to-install-rancher-2-5-in-docker-desktops-bundled-kubernetes-cluster-ebd5e1b0ae8"&gt;instruction&lt;/a&gt;) for cluster management.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-dual-boot"&gt;Dual-Boot?&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With WSL2 on top of a real Linux kernel, I do not find a need for a dual-boot system on my workstation. To be fair, only in the following scenarios should one consider installing a dual-boot system.&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;You need to work on a specify version of Linux Kernel. The kernel provided by Microsoft is called &amp;#8220;microsoft-standard-WSL2&amp;#8221;, and its pretty up to date (5.x)&lt;/li&gt;&#10;&lt;li&gt;You need to run GUI applications on Linux. Update: Microsoft has started developing GUI application support on WSL2, even though it usually takes time to mature.&lt;/li&gt;&#10;&lt;li&gt;You need to work on a distribution not available in Windows Store. WSL2 provides a kernel and it&amp;#8217;s up to developers to provide Linux distros in Windows store. Popular (and official) ones are: Ubuntu 20.04 LTS by Canonical Group, Debian by the Debian project, SUSE Linux Enterprise Server by SUSE, Kali Linux.&lt;/li&gt;&#10;&lt;li&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 class="wp-block-heading"&gt;Certificate Issuers&lt;/h2&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I have to use WSL2 mostly because I&amp;#8217;m forced to use a Windows laptop on my contracts. That also means that the Windows laptop has been configured to corporate firewall&amp;#8217;s packet inspection. When that is the case, they corporate IT usually automatically imports a firewall certificate to the Windows trust store. However, the WSL is missing this certificate. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The symptom would be that you cannot run certain curl command. For example, when I do the followings:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl -LO &lt;span style="color:#e6db74"&gt;&amp;#34;https://dl.k8s.io/release/&lt;/span&gt;&lt;span style="color:#66d9ef"&gt;$(&lt;/span&gt;curl -L -s https://dl.k8s.io/release/stable.txt&lt;span style="color:#66d9ef"&gt;)&lt;/span&gt;&lt;span style="color:#e6db74"&gt;/bin/linux/amd64/kubectl&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl: &lt;span style="color:#f92672"&gt;(&lt;/span&gt;60&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SSL certificate problem: unable to get local issuer certificate&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;More details here: https://curl.se/docs/sslcerts.html&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;curl failed to verify the legitimacy of the server and therefore could not&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;establish a secure connection to it. To learn more about this situation and&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;how to fix it, please visit the web page mentioned above. &#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This error message basically means that the website certificate cannot be trusted. To view the certificate, use Open SSL 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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;openssl s_client -connect dl.k8s.io:443 -servername dl.k8s.io | openssl x509 -text -noout | less&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In my case, I noticed that the certificate is a Zscaler issued certificate (firewall). While running the same command from my personal device returns a Goolge Trust issued certificate. This indicates that the certificate is changed by the proxy managed by the corporation. To fix this I need to export the certificate from Windows, and then import it in WSL. The &lt;a href="https://stackoverflow.com/questions/72167566/wsl-docker-curl-60-ssl-certificate-problem-unable-to-get-local-issuer-certi"&gt;answer&lt;/a&gt; in this post has good detailed steps.&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/05/ansible-directory-for-scalability-2-of-2/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Ansible at scale 2 of 2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/06/network-analyzer-capture-filter-and-display-filter/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Capture filter and Display filter in Network Analyzer&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Balloon steals memory from virtual machines</title><link>https://static.digihunch.com/2020/05/understanding-where-the-memory-goes-on-linux-vm/</link><pubDate>Thu, 07 May 2020 19:49:00 -0400</pubDate><guid>https://static.digihunch.com/2020/05/understanding-where-the-memory-goes-on-linux-vm/</guid><description>&lt;p class="wp-block-paragraph"&gt;This article is my experience with memory balloon on virtual machine.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I came across an ElasticSearch server (ESXi guest with 32GB physical memory) where the main process keeps dying of OOM. Even worse, after the OOM event, the free memory left is about 10G and Elastic Search cannot start because its JVM is set with -Xms16g in /etc/elasticsearch/jvm.options. So I need to address the OutOfMemory error.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To understand what triggered OOM, we can use dmesg or just check /var/log/message, where the memory snapshot by OOM killer is displayed during the kernel panic:&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;Apr 26 04:18:15 elastichost kernel: kworker/7:1 invoked oom-killer: gfp_mask=0x200d2, order=0, oom_score_adj=0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: kworker/7:1 cpuset=/ mems_allowed=0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: CPU: 7 PID: 13968 Comm: kworker/7:1 Kdump: loaded Not tainted 3.10.0-957.1.3.el7.x86_64 #1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 12/12/2018&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Workqueue: events_freezable vmballoon_work [vmw_balloon]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Call Trace:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa2961e41&amp;gt;] dump_stack+0x19/0x1b&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa295c86a&amp;gt;] dump_header+0x90/0x229&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa2301052&amp;gt;] ? ktime_get_ts64+0x52/0xf0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23581ef&amp;gt;] ? delayacct_end+0x8f/0xb0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23ba4e4&amp;gt;] oom_kill_process+0x254/0x3d0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23b9f8d&amp;gt;] ? oom_unkillable_task+0xcd/0x120&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23ba036&amp;gt;] ? find_lock_task_mm+0x56/0xc0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23bad26&amp;gt;] out_of_memory+0x4b6/0x4f0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa295d36e&amp;gt;] __alloc_pages_slowpath+0x5d6/0x724&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23c1105&amp;gt;] __alloc_pages_nodemask+0x405/0x420&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa240df68&amp;gt;] alloc_pages_current+0x98/0x110&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffc05f1f84&amp;gt;] vmballoon_work+0x454/0x6ff [vmw_balloon]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa22b9d4f&amp;gt;] process_one_work+0x17f/0x440&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa22bade6&amp;gt;] worker_thread+0x126/0x3c0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa22bacc0&amp;gt;] ? manage_workers.isra.25+0x2a0/0x2a0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa22c1c31&amp;gt;] kthread+0xd1/0xe0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa22c1b60&amp;gt;] ? insert_kthread_work+0x40/0x40&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa2974c37&amp;gt;] ret_from_fork_nospec_begin+0x21/0x21&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa22c1b60&amp;gt;] ? insert_kthread_work+0x40/0x40&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Mem-Info:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: active_anon:3649243 inactive_anon:439380 isolated_anon:0#012 active_file:480 inactive_file:693 isolated_file:0#012 unevictable:0 dirty:2 writeback:0 unstable:0#012 slab_reclaimable:77845 slab_unreclaimable:10219#012 mapped:10086 shmem:9596 pagetables:16727 bounce:0#012 free:50116 free_pcp:238 free_cma:0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Node 0 DMA free:15892kB min:32kB low:40kB high:48kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15992kB managed:15908kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:0kB slab_unreclaimable:16kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? yes&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: lowmem_reserve[]: 0 2829 31993 31993&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Node 0 DMA32 free:122768kB min:5972kB low:7464kB high:8956kB active_anon:471052kB inactive_anon:471040kB active_file:232kB inactive_file:460kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:3129216kB managed:2897760kB mlocked:0kB dirty:0kB writeback:0kB mapped:584kB shmem:300kB slab_reclaimable:23908kB slab_unreclaimable:3872kB kernel_stack:656kB pagetables:6440kB unstable:0kB bounce:0kB free_pcp:288kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:214 all_unreclaimable? no&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: lowmem_reserve[]: 0 0 29163 29163&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Node 0 Normal free:61804kB min:61576kB low:76968kB high:92364kB active_anon:14125920kB inactive_anon:1286480kB active_file:1688kB inactive_file:2312kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:30408704kB managed:29866500kB mlocked:0kB dirty:8kB writeback:0kB mapped:39760kB shmem:38084kB slab_reclaimable:287472kB slab_unreclaimable:36988kB kernel_stack:5680kB pagetables:60468kB unstable:0kB bounce:0kB free_pcp:804kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:698 all_unreclaimable? no&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: lowmem_reserve[]: 0 0 0 0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Node 0 DMA: 1*4kB (U) 0*8kB 1*16kB (U) 0*32kB 2*64kB (U) 1*128kB (U) 1*256kB (U) 0*512kB 1*1024kB (U) 1*2048kB (M) 3*4096kB (M) = 15892kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Node 0 DMA32: 407*4kB (UEM) 506*8kB (UEM) 431*16kB (UM) 364*32kB (M) 272*64kB (UM) 179*128kB (UM) 99*256kB (UM) 35*512kB (M) 11*1024kB (M) 2*2048kB (M) 0*4096kB = 123164kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Node 0 Normal: 15576*4kB (UM) 39*8kB (UM) 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 62616kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=1048576kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: 44652 total pagecache pages&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: 34162 pages in swap cache&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Swap cache stats: add 10884045, delete 10845872, find 3294122/3678936&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Free swap = 0kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Total swap = 2097148kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: 8388478 pages RAM&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: 0 pages HighMem/MovableOnly&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: 193436 pages reserved&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ pid ] uid tgid total_vm rss nr_ptes swapents oom_score_adj name&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 3164] 0 3164 47420 12996 100 6314 0 systemd-journal&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 3192] 0 3192 11158 2 24 174 -1000 systemd-udevd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 3198] 0 3198 66023 0 31 117 0 lvmetad&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6051] 0 6051 15511 20 29 138 -1000 auditd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6073] 81 6073 14557 83 32 88 -900 dbus-daemon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6075] 32 6075 18412 16 39 166 0 rpcbind&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6076] 0 6076 50404 0 37 171 0 gssproxy&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6077] 0 6077 5422 50 15 41 0 irqbalance&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6078] 0 6078 118943 155 85 362 0 NetworkManager&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6086] 0 6086 6594 47 18 41 0 systemd-logind&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6087] 0 6087 24892 0 42 402 0 VGAuthService&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6088] 0 6088 56746 113 58 246 0 vmtoolsd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6089] 999 6089 153086 130 61 1787 0 polkitd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6129] 38 6129 11817 39 27 140 0 ntpd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6464] 0 6464 56962 132 62 970 0 snmpd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6468] 0 6468 97733 4770 100 482 0 rsyslogd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6470] 0 6470 470477 6332 100 781 0 sh-metricbeat&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6472] 0 6472 250084 2279 72 2367 0 sh-filebeat&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6483] 0 6483 28189 26 57 231 -1000 sshd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6485] 0 6485 143455 107 97 2667 0 tuned&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6569] 0 6569 76290 625 41 188 0 avagent.bin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6574] 29 6574 12239 1 27 254 0 rpc.statd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6601] 0 6601 31572 30 18 129 0 crond&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6609] 0 6609 27523 1 10 32 0 agetty&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 7451] 494 7451 315970 36412 364 8550 0 node&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [11272] 0 11272 39154 0 80 336 0 sshd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [11277] 0 11277 28885 2 12 112 0 bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [16070] 495 16070 47122631 3994129 15027 457539 0 java&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [16264] 495 16264 18032 0 31 162 0 controller&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Out of memory: Kill process 16070 (java) score 512 or sacrifice child&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Killed process 16264 (controller) total-vm:72128kB, anon-rss:0kB, file-rss:0kB, shmem-rss:0kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: java invoked oom-killer: gfp_mask=0x201da, order=0, oom_score_adj=0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: java cpuset=/ mems_allowed=0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: CPU: 2 PID: 16265 Comm: java Kdump: loaded Not tainted 3.10.0-957.1.3.el7.x86_64 #1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Hardware name: VMware, Inc. VMware Virtual Platform/440BX Desktop Reference Platform, BIOS 6.00 12/12/2018&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Call Trace:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa2961e41&amp;gt;] dump_stack+0x19/0x1b&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa295c86a&amp;gt;] dump_header+0x90/0x229&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa2301052&amp;gt;] ? ktime_get_ts64+0x52/0xf0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23581ef&amp;gt;] ? delayacct_end+0x8f/0xb0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23ba4e4&amp;gt;] oom_kill_process+0x254/0x3d0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23b9f8d&amp;gt;] ? oom_unkillable_task+0xcd/0x120&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23ba036&amp;gt;] ? find_lock_task_mm+0x56/0xc0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23bad26&amp;gt;] out_of_memory+0x4b6/0x4f0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa295d36e&amp;gt;] __alloc_pages_slowpath+0x5d6/0x724&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23c1105&amp;gt;] __alloc_pages_nodemask+0x405/0x420&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa240df68&amp;gt;] alloc_pages_current+0x98/0x110&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23b6347&amp;gt;] __page_cache_alloc+0x97/0xb0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23b8fa8&amp;gt;] filemap_fault+0x298/0x490&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffc0484d0e&amp;gt;] __xfs_filemap_fault+0x7e/0x1d0 [xfs]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa22c2dc0&amp;gt;] ? wake_bit_function+0x40/0x40&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffc0484f0c&amp;gt;] xfs_filemap_fault+0x2c/0x30 [xfs]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23e444a&amp;gt;] __do_fault.isra.59+0x8a/0x100&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23e49fc&amp;gt;] do_read_fault.isra.61+0x4c/0x1b0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23e93a4&amp;gt;] handle_pte_fault+0x2f4/0xd10&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa23ebedd&amp;gt;] handle_mm_fault+0x39d/0x9b0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa296f5e3&amp;gt;] __do_page_fault+0x203/0x500&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa296f915&amp;gt;] do_page_fault+0x35/0x90&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [&amp;amp;lt;ffffffffa296b758&amp;gt;] page_fault+0x28/0x30&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Mem-Info:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: active_anon:3607073 inactive_anon:480522 isolated_anon:0#012 active_file:8 inactive_file:0 isolated_file:0#012 unevictable:0 dirty:0 writeback:1 unstable:0#012 slab_reclaimable:75170 slab_unreclaimable:10131#012 mapped:2070 shmem:9592 pagetables:16696 bounce:0#012 free:50006 free_pcp:72 free_cma:0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Node 0 DMA free:15892kB min:32kB low:40kB high:48kB active_anon:0kB inactive_anon:0kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:15992kB managed:15908kB mlocked:0kB dirty:0kB writeback:0kB mapped:0kB shmem:0kB slab_reclaimable:0kB slab_unreclaimable:16kB kernel_stack:0kB pagetables:0kB unstable:0kB bounce:0kB free_pcp:0kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:0 all_unreclaimable? yes&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: lowmem_reserve[]: 0 2829 31993 31993&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Node 0 DMA32 free:122560kB min:5972kB low:7464kB high:8956kB active_anon:471000kB inactive_anon:471076kB active_file:0kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:3129216kB managed:2897760kB mlocked:0kB dirty:0kB writeback:0kB mapped:292kB shmem:288kB slab_reclaimable:22832kB slab_unreclaimable:3752kB kernel_stack:672kB pagetables:6408kB unstable:0kB bounce:0kB free_pcp:272kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:215 all_unreclaimable? yes&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: lowmem_reserve[]: 0 0 29163 29163&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Node 0 Normal free:61572kB min:61576kB low:76968kB high:92364kB active_anon:13957292kB inactive_anon:1451012kB active_file:32kB inactive_file:0kB unevictable:0kB isolated(anon):0kB isolated(file):0kB present:30408704kB managed:29866500kB mlocked:0kB dirty:0kB writeback:4kB mapped:7988kB shmem:38080kB slab_reclaimable:277848kB slab_unreclaimable:36756kB kernel_stack:5664kB pagetables:60376kB unstable:0kB bounce:0kB free_pcp:16kB local_pcp:0kB free_cma:0kB writeback_tmp:0kB pages_scanned:500 all_unreclaimable? yes&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: lowmem_reserve[]: 0 0 0 0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Node 0 DMA: 1*4kB (U) 0*8kB 1*16kB (U) 0*32kB 2*64kB (U) 1*128kB (U) 1*256kB (U) 0*512kB 1*1024kB (U) 1*2048kB (M) 3*4096kB (M) = 15892kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Node 0 DMA32: 393*4kB (UEM) 490*8kB (UEM) 453*16kB (EM) 369*32kB (UEM) 269*64kB (M) 180*128kB (M) 98*256kB (M) 35*512kB (M) 12*1024kB (UM) 1*2048kB (M) 0*4096kB = 122148kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Node 0 Normal: 15440*4kB (UM) 1*8kB (U) 0*16kB 0*32kB 0*64kB 0*128kB 0*256kB 0*512kB 0*1024kB 0*2048kB 0*4096kB = 61768kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=1048576kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Node 0 hugepages_total=0 hugepages_free=0 hugepages_surp=0 hugepages_size=2048kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: 42975 total pagecache pages&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: 33308 pages in swap cache&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Swap cache stats: add 10884233, delete 10846914, find 3294127/3678944&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Free swap = 0kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Total swap = 2097148kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: 8388478 pages RAM&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: 0 pages HighMem/MovableOnly&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: 193436 pages reserved&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ pid ] uid tgid total_vm rss nr_ptes swapents oom_score_adj name&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 3164] 0 3164 47420 4016 100 6314 0 systemd-journal&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 3192] 0 3192 11158 2 24 174 -1000 systemd-udevd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 3198] 0 3198 66023 0 31 117 0 lvmetad&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6051] 0 6051 15511 20 29 138 -1000 auditd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6073] 81 6073 14557 78 32 88 -900 dbus-daemon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6075] 32 6075 18412 16 39 166 0 rpcbind&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6076] 0 6076 50404 0 37 171 0 gssproxy&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6077] 0 6077 5422 46 15 41 0 irqbalance&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6078] 0 6078 118943 155 85 362 0 NetworkManager&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6086] 0 6086 6594 42 18 41 0 systemd-logind&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6087] 0 6087 24892 0 42 402 0 VGAuthService&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6088] 0 6088 56746 91 58 246 0 vmtoolsd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6089] 999 6089 153086 130 61 1787 0 polkitd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6129] 38 6129 11817 36 27 140 0 ntpd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6464] 0 6464 56962 130 62 970 0 snmpd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6468] 0 6468 97733 1215 100 485 0 rsyslogd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6470] 0 6470 470477 6230 100 781 0 sh-metricbeat&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6472] 0 6472 250084 2279 72 2367 0 sh-filebeat&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6483] 0 6483 28189 26 57 231 -1000 sshd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6485] 0 6485 143455 107 97 2667 0 tuned&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6569] 0 6569 76290 625 41 188 0 avagent.bin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6574] 29 6574 12239 1 27 254 0 rpc.statd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6601] 0 6601 31572 27 18 129 0 crond&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 6609] 0 6609 27523 1 10 32 0 agetty&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [ 7451] 494 7451 315970 36412 364 8550 0 node&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [11272] 0 11272 39154 0 80 336 0 sshd&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [11277] 0 11277 28885 2 12 112 0 bash&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: [16070] 495 16070 47122631 3993992 15027 457699 0 java&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Out of memory: Kill process 16291 (java) score 512 or sacrifice child&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:15 elastichost kernel: Killed process 16070 (java) total-vm:188490524kB, anon-rss:15975968kB, file-rss:0kB, shmem-rss:0kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:16 elastichost systemd: elasticsearch.service: main process exited, code=killed, status=9/KILL&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:16 elastichost systemd: Unit elasticsearch.service entered failed state.&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Apr 26 04:18:16 elastichost systemd: elasticsearch.service failed.&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The line &amp;#8220;Free swap = 0kB&amp;#8221; suggest the trigger of OOM is out of swap. So does ElasticSearch contribute to the swap shortage?&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;ElasticSearch was the main process on the VM and I noticed that the OS did not &lt;a href="https://static.digihunch.com/2018/04/centos-remove-swap-safely/"&gt;disable swap&lt;/a&gt;, which does not align with the&lt;a href="https://www.elastic.co/guide/en/elasticsearch/reference/6.3/setup-configuration-memory.html"&gt; best practice&lt;/a&gt; from ElasticSearch community. In order to find out whether Elastic Search is pushed to use swap, we can get the process ID:&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;pidof java&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;ElasticSearch happens to be the only Java based process and the PID is 2283, the following command shows the swap usage by this process:&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;cat /proc/2283/status | grep VmSwap&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;If it shows a non-zero value, then ElasticSearch is using swap and you should expect some performance issues. We definitely should &lt;a href="https://static.digihunch.com/2018/04/centos-remove-swap-safely/"&gt;disable swap&lt;/a&gt; on ElasticSearch but does that solve the problem? Probably not because we didn&amp;#8217;t address what caused the memory pressure in the first place. Disabling swap most likely makes ElastciSearch last longer before something else such as shortage of available memory triggers OOM. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In search for the source of memory shortage, I checked the result of free command and the top command. The free command (-mh) shows the following:&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; total used free shared buff/cache available&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Mem: 31G 20G 10G 117M 243M 10G&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Swap: 2.0G 249M 1.8G&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;I tried to follow my example from a &lt;a href="https://static.digihunch.com/2020/04/how-memory-usage-adds-up-in-linux/"&gt;previous post &lt;/a&gt;to make sense of the memory reads. When I monitor process with top and watch for RSS column, I cannot identify a single process that even takes more than a few hundred megabytes. I&amp;#8217;ve downloaded a tool smem from epel repo, and the result of &amp;#8220;smem -kt&amp;#8221; suggest that the total RSS is about 372.2M:&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-large"&gt;&lt;img loading="lazy" decoding="async" width="1778" height="206" src="https://static.digihunch.com/wp-content/uploads/2020/05/image.png" alt="" class="wp-image-979"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;So there is about 19.6GB of memory usage unaccounted for. There is something that takes this much memory in the VM and haunting round even after OOM killer! &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Inspired by &lt;a href="https://unix.stackexchange.com/questions/259659/high-memory-usage-but-no-process-is-using-it"&gt;this&lt;/a&gt; post, I was able to identify the culprit, that is the memory balloon. We don&amp;#8217;t have access to the host but from the Guest OS, we can tell by vmware-toolbox-cmd (need to install yum package open-vm-tools):&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;vmware-toolbox-cmd stat balloon&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The result displays a whopping 20807 MB as &lt;a href="https://en.wikipedia.org/wiki/Memory_ballooning"&gt;memory balloon&lt;/a&gt;! &lt;a href="https://techdocs.broadcom.com/us/en/vmware-cis/vsphere/vsphere/6-5/vsphere-resource-management-6-5/administering-memory-resources/memory-reclamation/memory-balloon-driver.html"&gt;This&lt;/a&gt; needs to be sent to PaaS vendor for investigation but it is likely a result of memory over-allocation/over-commitment at host level, as well as the setup where the memory of guest is not reserved. Looking at the original log snippet, the line with &amp;#8220;events_freezable vmballoon_work&amp;#8221; is also an indicator of balloon causing the OOM.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Hypervisor needs memory ballooning to reclaim memory from guest. Since the guest OS does not expect the amount of physical memory to change, hypervisor has to maintain the illusion that the guest has its fixed amount of physical memory. The hypervisor first computes the amount of memory that needs to reclaim, then it leverage some low-level mechanism such as a balloon driver (a pseudo-device driver) installed on guest. The driver communicates with hypervisor and is told to allocate or de-allocate memory. If the driver is told to allocate memory to host, it tells the guest OS to pin the allocated pages into physical memory so they are locked and the physical memory available to guest OS is decreased. All these low level mechanisms explains why it is hard to account for memory consumption based on process running in Guest OS.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Memory balloon is a dynamic process and the hypervisor adjusts the size of balloon. However, the hypervisor, the guest OS and the application process (ElasticSearch in this case) may enter a nuance interaction:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&#10;&lt;li&gt;The hypervisor reclaims memory from guest OS (ballooning);&lt;/li&gt;&#10;&lt;li&gt;Guest OS panicked with OOM exception;&lt;/li&gt;&#10;&lt;li&gt;OOM picks a process to kill, based on oom_score. Unfortunately, the true culprit (balloon) is not visible to guest OS, hence exempted from being considered to kill.&lt;/li&gt;&#10;&lt;li&gt;By killing the application process (usually the main application for VM), a fair chunk of guest memory is freed up;&lt;/li&gt;&#10;&lt;li&gt;the balloon then became more aggressive on the guest as seeing more memory becomes &amp;#8220;available&amp;#8221;;&lt;/li&gt;&#10;&lt;li&gt;the application on guest then does not have minimum memory on guest OS to start;&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;How to solve this problem? There are several things to consider. On the hypervisor, keep the entire or part of the guest memory reserved for start of application. Tune the OOM scoring so the non-critical application get killed. Implement application daemon, etc.&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/04/cassandra-data-model-as-opposed-to-relational-database/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Cassandra data model (as opposed to relational model)&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/05/revamp-ansible-directory-for-scalability-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;Ansible at scale 1 of 2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>How memory usage adds up in Linux</title><link>https://static.digihunch.com/2020/04/how-memory-usage-adds-up-in-linux/</link><pubDate>Sun, 19 Apr 2020 21:12:56 -0400</pubDate><guid>https://static.digihunch.com/2020/04/how-memory-usage-adds-up-in-linux/</guid><description>&lt;p class="wp-block-paragraph"&gt;There are too many metrics that describes some aspects about memory in Linux. This posting will make sense of those common metrics in Linux, CentOS as an example.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The most fundamental command is free and my favourite switch is -h for human readable reads. You can use -m, -k, -b for different units. The result looks like this:&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; total used free shared buff/cache available&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Mem: 32780168 16832160 3200408 101356 12747600 15399528&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Swap: 2097148 2055148 42000&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Swap is essentially disk space and many application such as Cassandra, ElasticSearch recommend disabling swap as best practice and they do not want disk speed to drag the performance of memory. Many suggest that swap is not needed in today&amp;#8217;s era at all given the amount of memory for cheap. This is &lt;a href="https://askubuntu.com/questions/291378/do-we-still-need-swap-partitions-on-servers"&gt;debatable&lt;/a&gt;. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;With the row for Mem, the four columns should add up to the total, as suggested in the chart below. &lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="http://blog.yufeng.info/wp-content/uploads/2013/01/free1.jpg" alt=""/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;total = free + used + shared + buff/cache &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The four columns from free command output are supposed to always add up to the physical memory size. This command simplifies things quite a bit and each of these values are actually taken from certain lines in /proc/meminfo:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-background" style="background-color:#e7f5fe"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Metric from free command&lt;/td&gt;&lt;td&gt;Metric in /proc/meminfo&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;total&lt;/td&gt;&lt;td&gt;MemTotal&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;used&lt;/td&gt;&lt;td&gt;??&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;free&lt;/td&gt;&lt;td&gt;MemFree&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;shared&lt;/td&gt;&lt;td&gt;Shmem&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;buff/cache&lt;/td&gt;&lt;td&gt;Cached + Slab&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;available&lt;/td&gt;&lt;td&gt;MemAvailable&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The buffer and cache (and even swap) can be freed by &lt;a href="https://www.tecmint.com/clear-ram-memory-cache-buffer-and-swap-space-on-linux/"&gt;command&lt;/a&gt;. The value of used doesn&amp;#8217;t seem to come from anwhere in /proc/meminfo, but it should be calculable from the memory used per process, which can be seen from top command.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the result of top command, the column RSS (resident set size) is from the VmRSS value in /proc/&amp;lt;pid&amp;gt;/status, it is the actual physical memory consumed by the process. This value is originally from the second read in /proc/&amp;lt;pid&amp;gt;/statm, which represents the number of pages. For example:&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;[ghunch@centos ~]$ cat /proc/6495/status | grep VmRSS ; cat /proc/6495/statm&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;VmRSS:&#9;20852916 kB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;49829626 5213229 1212275 1 0 5773980 0&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[ghunch@centos ~]$ getconf PAGE_SIZE&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;4096&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Linux default page size is 4096 or 4K, so in the result from above, 5213229 x 4kB = 20852916 kB, which is the size of memory taken by process ID 6459. Therefore if we go through all processes and add up the VmRSS, we should get (close to) the used memory?&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;But wait a second, we have not account for slab info (memory used by kernel) yet, which is displayed in /proc/slabinfo. To calculate the total size taken by slab, we use &amp;lt;num_objs&amp;gt; and &amp;lt;objsize&amp;gt; columns from /proc/slabinfo.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Apart from that there is &lt;a href="https://en.wikipedia.org/wiki/Page_table"&gt;page table&lt;/a&gt;, the table that stores the mapping between virtual address and physical address, is stored in the physical memory as well and the size is specified in the PageTables entry in /proc/meminfo. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Now our equation becomes:&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Used Memory = (RSS for all processes) + (all objects in slab) + (page table)&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We can use the following script to calculate the used memory and compare it with free command output.&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#/bin/bash&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; PROC in &lt;span style="color:#e6db74"&gt;`&lt;/span&gt;ls /proc/|grep &lt;span style="color:#e6db74"&gt;&amp;#34;^[0-9]&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;do&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; -f /proc/$PROC/statm &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; TEP&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;cat /proc/$PROC/statm | awk &lt;span style="color:#e6db74"&gt;&amp;#39;{print ($2)}&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; RSS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;expr $RSS + $TEP&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;done&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RSS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;expr $RSS &lt;span style="color:#ae81ff"&gt;\*&lt;/span&gt; 4&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PageTable&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;grep PageTables /proc/meminfo | awk &lt;span style="color:#e6db74"&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SlabInfo&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;cat /proc/slabinfo |awk &lt;span style="color:#e6db74"&gt;&amp;#39;BEGIN{sum=0;}{sum=sum+$3*$4;}END{print sum/1024/1024}&amp;#39;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo $RSS&lt;span style="color:#e6db74"&gt;&amp;#34;KB&amp;#34;&lt;/span&gt;, $PageTable&lt;span style="color:#e6db74"&gt;&amp;#34;KB&amp;#34;&lt;/span&gt;, $SlabInfo&lt;span style="color:#e6db74"&gt;&amp;#34;MB&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;printf &lt;span style="color:#e6db74"&gt;&amp;#34;rss+pagetable+slabinfo=%sMB\n&amp;#34;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;`&lt;/span&gt;echo $RSS/1024 + $PageTable/1024 + $SlabInfo|bc&lt;span style="color:#e6db74"&gt;`&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;free -m&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Running it require root access and the bc package installed. The result is most likely greater than the used memory value. Below is the result from my server:&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;89925884KB, 201788KB, 3303.92MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rss+pagetable+slabinfo=91318.92MB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; total used free shared buff/cache available&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Mem: 128772 87032 726 498 41013 40346&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Swap: 2047 3 2044&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;So the result is over by (91318 &amp;#8211; 87032) = 4286M. This is due to shared memory. The RSS value from above include memory from shared libraries as long as the pages from those libraries are in the memory. If multiple processes use the same library, the memory from shared library is counted multiple times. Check out the difference between &lt;a href="https://en.wikipedia.org/wiki/Resident_set_size"&gt;RSS&lt;/a&gt; and &lt;a href="https://en.wikipedia.org/wiki/Proportional_set_size"&gt;PSS&lt;/a&gt; (proportional set size) &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;[Disclaimer] The chart and script are stolen from this authors &lt;a href="http://www.programmersought.com/article/6127180173/"&gt;post&lt;/a&gt;.&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/04/common-local-git-operations/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Common local Git operations&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/04/cassandra-data-model-as-opposed-to-relational-database/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Cassandra data model (as opposed to relational model)&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Introduction to Authentication Frameworks (PAM and SSPI)</title><link>https://static.digihunch.com/2020/03/introduction-to-authentication-frameworks-pam-and-sspi/</link><pubDate>Tue, 24 Mar 2020 20:19:00 -0400</pubDate><guid>https://static.digihunch.com/2020/03/introduction-to-authentication-frameworks-pam-and-sspi/</guid><description>&lt;p class="wp-block-paragraph"&gt;This article gives a very brief high-level introduction to PAM (Pluggable Authentication Module) and SSPI (Security Support Provider Interface) as authentication frameworks in Linux and Windows respectively. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-pam"&gt;PAM&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The &lt;a href="https://web.archive.org/web/20211022181300/https://ldapwiki.com/wiki/Pluggable%20Authentication%20Modules"&gt;Pluggable Authentication Module (PAM) architecture&lt;/a&gt; provides a powerful abstraction for user IAM using pluggable authentication model Unix platforms. It defines a generic API for authentication and hides the underlying mechanisms. Thanks to PAM, administrators can plug different authentication modules and protocols into Linux. This makes different authentication methods and protocols available to applications running on Linux. Here is some of authentication methods and protocols that PAM supports:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Unix file-based authentication (using /etc/passwd or /etc/shadow)&lt;/li&gt;&#10;&lt;li&gt;LDAP-based authentication&lt;/li&gt;&#10;&lt;li&gt;Kerbero-based authentication&lt;/li&gt;&#10;&lt;li&gt;NTLM-based authentication&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;PAM obviates the need for a separate authentication schemes. It exports methods of the various libraries under its auspices to calling applications. Here is a diagram for PAM on &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/managing_smart_cards/pluggable_authentication_modules"&gt;Redhat&lt;/a&gt;.&lt;/p&gt;&#10;&lt;figure class="wp-block-image size-full"&gt;&lt;img loading="lazy" decoding="async" width="765" height="678" src="https://static.digihunch.com/wp-content/uploads/2023/01/pam.jpg" alt="" class="wp-image-8107" srcset="https://static.digihunch.com/wp-content/uploads/2023/01/pam.jpg 765w, https://static.digihunch.com/wp-content/uploads/2023/01/pam-300x266.jpg 300w" sizes="auto, (max-width: 765px) 100vw, 765px" /&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;PAM can also enbable single-sign-on(SSO) on the UNIX platform. If the password used for different services are identical, PAM can be used to share the password transparently between the application&amp;#8217;s possibly different authentication mechanisms. PAM is configured in /etc/pam.d/ directory.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The Windows equivalent of PAM is the Security Support Provider Interface (SSPI) and its Security Support Provider (SSP) Modules. For example /etc/pam./login manages login module, /tec/pam.d/imap manages imap module.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-sspi"&gt;SSPI&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://docs.microsoft.com/en-us/windows-server/security/windows-authentication/windows-authentication-architecture"&gt;Windows Authentication Architecture&lt;/a&gt; involves Local Security Authority (LSA, to authenticate users to local computer only and is managed in local security policy) and Security Support Provider Interface (SSPI).&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://docs.microsoft.com/en-us/windows-server/security/windows-authentication/security-support-provider-interface-architecture"&gt;SSPI&lt;/a&gt; is the API that obtains integrated security service for authentication, message integrity, message privacy, and security quality-of-service for any distributed application protocol. SSPI is the implementation of the Generic Security Service API (GSS-API) in Windows operating system. Applications and infrastructure services authenticate users by using the SSPI to abstract calls for authentication. This way, developers do not need to understand the complexities of specific authentication protocols or build authentication protocols into their applications. &lt;a href="https://docs.microsoft.com/en-us/windows-server/security/windows-authentication/security-support-provider-interface-architecture"&gt;Here &lt;/a&gt;is the architecture diagram:&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://docs.microsoft.com/en-us/windows-server/security/media/security-support-provider-interface-architecture/authn_securitysupportproviderinterfacearchitecture.jpg" alt="Diagram showing the Security Support Provider Interface Architecture"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The SSPI in Windows provides a mechansim that carries authentication token over the existing communication channel between the client computer and the server. When two computers or devices need to be authenticated so that they can communicate securely, the requests for authentication are routed to the SSPI, which completes the authentication process, regardless of the network protocol currently in use. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Here is some exampls of SSPs that are supported by SSPI:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Kerberos SSP (default for Active Directory)&lt;/li&gt;&#10;&lt;li&gt;NTLM SSP&lt;/li&gt;&#10;&lt;li&gt;Digest SSP&lt;/li&gt;&#10;&lt;li&gt;Negotiate SSP (based on &lt;a href="https://en.wikipedia.org/wiki/SPNEGO"&gt;SPNEGO&lt;/a&gt;, RFC4178)&lt;/li&gt;&#10;&lt;li&gt;Credential SSP&lt;/li&gt;&#10;&lt;li&gt;Negotiate Extension SSP&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Some SSPs such as Kerberos SSP and NTLM SSP use a single protocol. Some (e.g. Negotiate SSP and Credential SSP) combine several protocols to allow application to select what security mechanism they wish to use and negotiate with authentication services.&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/03/authentication-mechanisms-under-simple-authentication-and-security-layer-sasl/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;SASL Authentication Mechanisms&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/03/ntlm-and-kerberos/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;NTLM and Kerberos protocols&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>High Availability and Load Balancer</title><link>https://static.digihunch.com/2020/01/several-ways-to-ensure-high-availability/</link><pubDate>Wed, 22 Jan 2020 20:49:00 -0400</pubDate><guid>https://static.digihunch.com/2020/01/several-ways-to-ensure-high-availability/</guid><description>&lt;h3 class="wp-block-heading" id="h-overview"&gt;Overview&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Fault tolerance and high availability are two architectural characteristics that people often confuse with each other. High availability focuses on minimizing downtime. It guarantees uptime, but not performance in the event of component failures. Fault tolerance, on the other hand, focuses on stable capacity even in the event of component failures. Fault tolerance has higher bar, and therefore is more expensive. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Suppose an application requires four servers to meet performance goal. Placing two servers in each of the two AZs will meet HA criteria but not FT requirement. In the event of an AZ failure, application can operate at degraded performance yet still be highly available. However, FT requires stable capacity and to meet FT requirement, we&amp;#8217;d have to place four servers in each AZ. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;High availability can be achieved either by clustering, or load balancing. A cluster involves several nodes, all able to perform the same function, but may take different roles at different times (e.g. primary, standby) in order for the cluster to perform its function as a single system. In Linux, clustering is implemented by pacemaker or corosync. With a high load system, it is common to set up load balancing system to achieve high availability (and fault tolerance).&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-load-balancing"&gt;Load balancing&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The idea of load balancing is simple: load goes high and we want to scale horizontally instead of simply upgrading server hardware. At a high level, there has been three approaches to load balancing:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;&lt;strong&gt;DNS rotating:&lt;/strong&gt; (aka. DNS round robin) DNS record resolves to multiple IPs, very simple and cheap to implement. Since DNS is cached, the load distribution will come imbalanced and it&amp;#8217;s hard to re-balance, making this a very limited approach;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Hardware Load Balancer&lt;/strong&gt;: using dedicated hardware device to configure load balancing. This option is expensive and only enterprises can afford it (&lt;a class="rank-math-link" href="https://kemptechnologies.com/compare-kemp-to-f5-big-ip-ltm-citrix-netscaler-mpx-load-balancers/"&gt;here&lt;/a&gt;&amp;#8216;s some pricing information). A classic load balancer operates at layer 3 and 4, which is also known as POLB (plain old load balancer). It is the core functionality of hardware load balancer. The hardware load balancer on the market today usually come with a variety of add-on features, such as advanced load balancing (L4, L7 path-based, script driven), compression, caching, SSL offloading, and even DDoS mitigation, etc. The whole suite of features makes it an Application Delivery Controller (ADC). Therefore many refer to hardware load balancer as &lt;a href="https://www.f5.com/company/blog/go-beyond-polb-plain-old-load-balancing"&gt;hardware-based ADC&lt;/a&gt; to highlight the features in addition to POLB. Hardware-based ADCs ship with manufactures hardware, with specialized processors, advanced network hardware, and often &lt;a href="https://www.f5.com/services/resources/white-papers/software-defined-hardware-enabling-performance-and-agility-with-the-big-ip-iseries-architecture"&gt;ASIC&lt;/a&gt; (application specific integrated circuit). At a higher expense, they have better reliability and capacity. Some major market players are:&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;F5 &amp;#8211; &lt;a class="rank-math-link" href="https://www.f5.com/services/resources/white-papers"&gt;Big IP&lt;/a&gt;, F5 also has a &lt;a href="https://devcentral.f5.com/s/articles/what-is-load-balancing-24740"&gt;good article &lt;/a&gt;about history of load balancer.&lt;/li&gt;&#10;&lt;li&gt;Cisco &amp;#8211; Citrix A&lt;a href="https://www.citrix.com/products/citrix-adc/"&gt;https://www.citrix.com/products/citrix-adc/&lt;/a&gt;DC (formerly NetScaler ADC)&lt;/li&gt;&#10;&lt;li&gt;A10 Networks &amp;#8211; &lt;a class="rank-math-link" href="https://www.a10networks.com/products/thunder-adc/"&gt;Thunder&lt;/a&gt; (general) and &lt;a class="rank-math-link" href="http://docs.hc.a10networks.com/2.2.4/ads-intro.html"&gt;Lightning&lt;/a&gt; (cloud)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Software Load Balancer:&lt;/strong&gt; using software to achieve load balancing. These solutions are affordable, and usually open-source. They can be loaded on commodity hardware (including NIC). Some (e.g. &lt;a class="rank-math-link" href="https://www.nginx.com/resources/glossary/application-delivery-controller/"&gt;Nginx&lt;/a&gt;) refers to themselves as software-based ADC. Major players are:&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;HA Proxy&lt;/li&gt;&#10;&lt;li&gt;Nginx&lt;/li&gt;&#10;&lt;li&gt;Linux Virtual Server (LVS, L4 only)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The hardware ADCs are usually supported commercially and there are plenty of resources from their white papers. There is an ongoing debate about whether one is better than the other. However, there is no doubt that a software-based load balancer is more approachable as open-source tools. The line between software and hardware load balancers becomes blurred today as hardware vendors try to adapt their software appliance to commodity hardware. Check out &lt;a href="https://www.nginx.com/blog/not-all-software-load-balancers-are-created-equal/"&gt;this&lt;/a&gt; article. The rest of this post, will focus on software-based load balancer. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-software-based-load-balancer"&gt;Software-based load balancer&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We explained that ADC (application delivery controller) is an expanded set of features from load balancer, and will only cover the load balancer part of the feature set in this article.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://www.haproxy.org/" class="rank-math-link"&gt;HAProxy&lt;/a&gt; supports both layer 4 and layer 7 load balancing. It supports load balancing based on cookie and session, as well as health check. Since it is layer 4 load balancing, it supports any TCP protocol such as read traffic for MySQL. &amp;nbsp;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://www.nginx.com/" class="rank-math-link"&gt;Nginx&lt;/a&gt; is a high-performance, event-driven, cross-platform layer 7 load balancing application. It works as a reverse proxy where it receives request for the Internet and forwards it to (upstream) internal servers. It consumes less memory than many of its alternatives for layer 7 load balancing. There are many strategies for load balancing such as round robin, by weight, by hash of requesting IP, by upstream response time, or by URL hash. It supports 20-30 k concurrent connections, and support compression and health check. It is known to be very stable and common for small and medium volume. Nginx has a commercial counterpart Nginx Plus with advanced features.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Nginx and HA proxy are commonly used in front end load balancing. For backend traffic such as database (e.g. separating read write traffic), LVS can be used.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-linux-virtual-server"&gt;Linux Virtual Server&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/4/html/virtual_server_administration/ch-lvs-overview-vsa" class="rank-math-link"&gt;LVS&lt;/a&gt; (Linux Virtual Server) is part of standard Linux kernel. It performs layer 4 load balancing based on TCP or UDP and therefore consumes less memory and CPU. Compared to layer 7 load balancing, the performance is generally higher, and the configuration is less complex (with simpler routing rules). &lt;a href="http://www.linuxvirtualserver.org/" class="rank-math-link"&gt;LVS&lt;/a&gt; is usually configured in a &lt;a href="http://www.linuxvirtualserver.org/architecture.html" class="rank-math-link"&gt;common cluster architecture&lt;/a&gt; involving these components:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Load balancer: the front-end machine of the whole cluster systems, and balances requests from clients among a set of servers, so that the clients consider that all the services is from a single IP address.&lt;/li&gt;&#10;&lt;li&gt;Server cluster: set of servers running actual business workload&lt;/li&gt;&#10;&lt;li&gt;Shared storage: a shared storage space for the servers, such as NFS&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://i.imgur.com/EU0gAUv.png" alt=""/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Load balancer is the single entry-point of server cluster systems, it can run&amp;nbsp;IPVS&amp;nbsp;that implements IP load balancing techniques inside the Linux kernel, or&amp;nbsp;KTCPVS&amp;nbsp;that implements application-level load balancing inside the Linux kernel. When IPVS is used, all the servers are required to provide the same services and contents, the load balancer forward a new client request to a server according to the specified scheduling algorithms and the load of each server. No matter which server is selected, the client should get the same result. When KTCPVS is used, servers can have different contents, the load balancer can forward a request to a different server according to the content of request. Since KTCPVS is implemented inside the Linux kernel, the overhead of relaying data is minimal, so that it can still have high throughput.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;IPVS is also called layer-4 switching, it directs TCP/UDP requests to the real servers behind load balancer. It works in three modes:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&#10;&lt;li&gt;Network Address Translation (NAT)&lt;/li&gt;&#10;&lt;li&gt;Direct Routing (DR)&lt;/li&gt;&#10;&lt;li&gt;Tunnel mode (TUN)&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;These are three packet-forwarding methods in IPVS. The IPVS is implemented as a module over the netfilter framework, similar to &lt;a href="https://static.digihunch.com/2018/10/redhat-firewall-configuration-firewalld-vs-iptables/" class="rank-math-link"&gt;iptables&lt;/a&gt;, which is also built on top of netfilter, based on chain and rules.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading" id="h-summary"&gt;Summary &lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We had an overview of high availability, and then expanded on load balancing, an important mechanism to implement high availability. We touched on both hardware-based and software-based load balancing technologies, and dived a little more into Linux Virtual Server. It is worth-noting that LVS is also the foundation of kube-proxy, the load balancing mechanism used in Kubernetes.&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/01/nginx-as-a-reverse-proxy-for-nifi/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Nginx as a reverse proxy for Nifi web UI and Kibana&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/02/everything-about-the-domain/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Introduction to Active Directory (AD)&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Nginx as a reverse proxy for Nifi web UI and Kibana</title><link>https://static.digihunch.com/2020/01/nginx-as-a-reverse-proxy-for-nifi/</link><pubDate>Thu, 16 Jan 2020 22:22:51 -0400</pubDate><guid>https://static.digihunch.com/2020/01/nginx-as-a-reverse-proxy-for-nifi/</guid><description>&lt;p class="wp-block-paragraph"&gt;Nginx can act as a application neutral proxy. One example is to front Nifi. The nifi default configuration provides an HTTP access point, specified in the following entries in nifi.properties:&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;nifi.web.http.host=192.168.133.5&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nifi.web.http.port=8080&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Nifi can provide secure port by commenting out the lines above and provide the followings:&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;nifi.web.https.host=192.168.133.5&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;nifi.web.https.port=8083&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;However, it does require configuring JKS keystore for Java, as well as authentication. Customers with existing AD servers are likely to require authentication via LDAP. While Nifi does support LDAP integration according to its &lt;a href="https://nifi.apache.org/docs/nifi-docs/html/administration-guide.html#ldap_login_identity_provider"&gt;administration guide&lt;/a&gt;. The configuration is quite involving. You need to configure the identity provider, as well as authorizes. I have personally spent a couple days on this without much progress. The information in the logging isn&amp;#8217;t to the point. Restarting nifi also is a long process, making it painful to troubleshoot. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I then moved to Nginx (open-source) as an alternative and it is quite enlightening. I already knew that the SSL termination in nginx is super easy to configure. This time I learned that the opensource community even has a support for LDAP integration. Here is a diagram of how it works:&lt;/p&gt;&#10;&lt;p class="has-text-align-center wp-block-paragraph"&gt;&lt;svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="542px" viewBox="-0.5 -0.5 542 272" style="max-width:100%;max-height:272px;"&gt;&lt;defs&gt;&lt;linearGradient x1="0%" y1="0%" x2="0%" y2="100%" id="mx-gradient-ffffff-1-33ebff-1-s-0"&gt;&lt;stop offset="0%" style="stop-color:#FFFFFF"&gt;&lt;/stop&gt;&lt;stop offset="100%" style="stop-color:#33EBFF"&gt;&lt;/stop&gt;&lt;/linearGradient&gt;&lt;/defs&gt;&lt;g&gt;&lt;rect x="0" y="0" width="540" height="270" fill="#f5f5f5" stroke="#666666" pointer-events="all"&gt;&lt;/rect&gt;&lt;rect x="10" y="75" width="60" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 90px; margin-left: 12px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Client&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="40" y="94" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Client&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="169.25" y="230" width="118.5" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 116px; height: 1px; padding-top: 245px; margin-left: 171px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Active Directory&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="229" y="249" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Active Directory&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="430" y="10" width="85" height="70" fill="#ffffff" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 83px; height: 1px; padding-top: 17px; margin-left: 432px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Container1&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="473" y="29" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Container1&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="445" y="40" width="55" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 53px; height: 1px; padding-top: 55px; margin-left: 447px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Nifi&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="473" y="59" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Nifi&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="430" y="120" width="85" height="70" fill="#ffffff" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 83px; height: 1px; padding-top: 127px; margin-left: 432px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Container2&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="473" y="139" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Container2&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="445" y="150" width="55" height="30" rx="4.5" ry="4.5" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 53px; height: 1px; padding-top: 165px; margin-left: 447px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;Nifi&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="473" y="169" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;Nifi&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="140" y="20" width="177" height="170" fill="#fff2cc" stroke="#d6b656" pointer-events="all"&gt;&lt;/rect&gt;&lt;rect x="140" y="20" width="177" height="170" fill="#ffffff" stroke="#000000" stroke-dasharray="3 3" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 175px; height: 1px; padding-top: 27px; margin-left: 142px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; text-decoration: underline; white-space: normal; word-wrap: normal; "&gt;Container&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="229" y="39" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle" text-decoration="underline"&gt;Container&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="155" y="50" width="144" height="60" rx="9" ry="9" fill="#ffffff" stroke="#000000" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 142px; height: 1px; padding-top: 57px; margin-left: 157px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; text-decoration: underline; white-space: normal; word-wrap: normal; "&gt;Nginx process&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="227" y="69" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle" text-decoration="underline"&gt;Nginx process&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="165" y="76" width="120" height="28" rx="4.2" ry="4.2" fill="url(#mx-gradient-ffffff-1-33ebff-1-s-0)" stroke="#6c8ebf" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 83px; margin-left: 167px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; text-decoration: underline; white-space: normal; word-wrap: normal; "&gt;http_auth_request&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="225" y="95" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle" text-decoration="underline"&gt;http_auth_request&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;rect x="155" y="150" width="145" height="30" rx="4.5" ry="4.5" fill="#fff2cc" stroke="#d6b656" pointer-events="all"&gt;&lt;/rect&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 143px; height: 1px; padding-top: 165px; margin-left: 157px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; white-space: normal; word-wrap: normal; "&gt;ldap-auth daemon&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="228" y="169" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;ldap-auth daemon&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 228 104.81 L 227.57 143.63" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 227.51 148.88 L 224.09 141.84 L 227.57 143.63 L 231.09 141.92 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 125px; margin-left: 228px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "&gt;http&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="228" y="129" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;http&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 285 83 L 438.73 56.1" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 443.9 55.19 L 437.61 59.85 L 438.73 56.1 L 436.4 52.95 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 55px; margin-left: 370px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #FFFFCC; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "&gt;d&lt;font color="#000000"&gt;http&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="370" y="58" fill="#FFFFCC" font-family="Helvetica" font-size="11px" text-anchor="middle"&gt;dhttp&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 285 97 L 439.14 162.51" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 443.97 164.56 L 436.16 165.05 L 439.14 162.51 L 438.9 158.6 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 120px; margin-left: 370px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #FFFFCC; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "&gt;&lt;font color="#000000"&gt;http&lt;/font&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="370" y="124" fill="#FFFFCC" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;http&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 228.37 223.63 L 227.63 186.37" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 228.48 228.88 L 224.84 221.95 L 228.37 223.63 L 231.84 221.81 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 227.52 181.12 L 231.16 188.05 L 227.63 186.37 L 224.16 188.19 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 205px; margin-left: 228px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 11px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "&gt;LDAP&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="228" y="208" fill="#000000" font-family="Helvetica" font-size="11px" text-anchor="middle"&gt;LDAP&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;path d="M 76.37 90 L 158.63 90" fill="none" stroke="#000000" stroke-miterlimit="10" pointer-events="stroke"&gt;&lt;/path&gt;&lt;path d="M 71.12 90 L 78.12 86.5 L 76.37 90 L 78.12 93.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;path d="M 163.88 90 L 156.88 93.5 L 158.63 90 L 156.88 86.5 Z" fill="#000000" stroke="#000000" stroke-miterlimit="10" pointer-events="all"&gt;&lt;/path&gt;&lt;g transform="translate(-0.5 -0.5)"&gt;&lt;switch&gt;&lt;foreignObject style="overflow: visible; text-align: left;" pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"&gt;&lt;div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 90px; margin-left: 106px;"&gt;&lt;div style="box-sizing: border-box; font-size: 0; text-align: center; "&gt;&lt;div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: #000000; line-height: 1.2; pointer-events: all; background-color: #ffffff; white-space: nowrap; "&gt;https&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/foreignObject&gt;&lt;text x="106" y="94" fill="#000000" font-family="Helvetica" font-size="12px" text-anchor="middle"&gt;https&lt;/text&gt;&lt;/switch&gt;&lt;/g&gt;&lt;/g&gt;&lt;/svg&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This approach is outlined in a &lt;a href="https://www.nginx.com/blog/nginx-plus-authenticate-users/"&gt;blog post&lt;/a&gt; on &lt;a href="https://www.nginx.com/"&gt;Nginx &lt;/a&gt;website. The &lt;a href="https://github.com/nginxinc/nginx-ldap-auth"&gt;ldap-auth daemon&lt;/a&gt; is implemented in Python can can be wrapped up as a systemd service. Once a client sends a request in https, security layer is terminated in nginx, and an authentication request in http is sent to the ldap-auth daemon, which proxies converts the request into LDAP searches and proxies it over to customer&amp;#8217;s Active Directory server, for authentication. Once authenticated, the http request can make to one of the backend container or server which hosts Nifi. Below is an example of how this can be configure on RedHat.&lt;/p&gt;&#10;&lt;h4 class="wp-block-heading"&gt;Install python3 and python-ldap&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;RedHat may have both python2 and python3 pre-installed, python2 being the default. We do not want to change the default because other applications such as yum still depends on python2 as of early 2020.&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum -y install python3&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum -y install gcc python3-devel openldap-devel&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pip3 install python-ldap&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Once python3 is installed, pip3 will be available and we use that to install python-ldap. This is a module in Python3 that will be used by the script that act as ldap daemon.&lt;/p&gt;&#10;&lt;h4 class="wp-block-heading"&gt;Configure ldap-auth daemon as systemd service&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the github project for &lt;a href="https://github.com/nginxinc/nginx-ldap-auth"&gt;ldap-auth&lt;/a&gt;, download nginx-ldap-auth-daemon.py to local location such as /usr/bin, then we create &lt;a href="https://github.com/nginxinc/nginx-ldap-auth/blob/master/nginx-ldap-auth-daemon.py"&gt;nginx-ldap-auth.service&lt;/a&gt; in /etc/systemd/system/ with the following content.&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-python" data-lang="python"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[Unit]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Description&lt;span style="color:#f92672"&gt;=&lt;/span&gt;LDAP authentication helper &lt;span style="color:#66d9ef"&gt;for&lt;/span&gt; Nginx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;After&lt;span style="color:#f92672"&gt;=&lt;/span&gt;network&lt;span style="color:#f92672"&gt;.&lt;/span&gt;target network&lt;span style="color:#f92672"&gt;-&lt;/span&gt;online&lt;span style="color:#f92672"&gt;.&lt;/span&gt;target&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[Service]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Type&lt;span style="color:#f92672"&gt;=&lt;/span&gt;simple&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;User&lt;span style="color:#f92672"&gt;=&lt;/span&gt;root&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Group&lt;span style="color:#f92672"&gt;=&lt;/span&gt;root&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WorkingDirectory&lt;span style="color:#f92672"&gt;=/&lt;/span&gt;var&lt;span style="color:#f92672"&gt;/&lt;/span&gt;run&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ExecStart&lt;span style="color:#f92672"&gt;=/&lt;/span&gt;usr&lt;span style="color:#f92672"&gt;/&lt;/span&gt;bin&lt;span style="color:#f92672"&gt;/&lt;/span&gt;python3 &lt;span style="color:#f92672"&gt;/&lt;/span&gt;usr&lt;span style="color:#f92672"&gt;/&lt;/span&gt;bin&lt;span style="color:#f92672"&gt;/&lt;/span&gt;nginx&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ldap&lt;span style="color:#f92672"&gt;-&lt;/span&gt;auth&lt;span style="color:#f92672"&gt;-&lt;/span&gt;daemon&lt;span style="color:#f92672"&gt;.&lt;/span&gt;py&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;KillMode&lt;span style="color:#f92672"&gt;=&lt;/span&gt;process&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;KillSignal&lt;span style="color:#f92672"&gt;=&lt;/span&gt;SIGINT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Restart&lt;span style="color:#f92672"&gt;=&lt;/span&gt;on&lt;span style="color:#f92672"&gt;-&lt;/span&gt;failure&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;[Install]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;WantedBy&lt;span style="color:#f92672"&gt;=&lt;/span&gt;multi&lt;span style="color:#f92672"&gt;-&lt;/span&gt;user&lt;span style="color:#f92672"&gt;.&lt;/span&gt;target&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then, run the following command to load, start and check nginx-ldap-auth service.&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl reload-daemon&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl start nginx-ldap-auth&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;systemctl status nginx-ldap-auth&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This service will be up and listening to port 8888 for http traffic.&lt;/p&gt;&#10;&lt;h4 class="wp-block-heading"&gt;Configure Nginx&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt; Then configure nginx with the following entries in its default.conf file, typically located in /etc/nginx/conf.d.&amp;nbsp; &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-xml" data-lang="xml"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;upstream nifibackend {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; # default: round robin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server container1.nifi.digihunch.com:8080;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server container2.nifi.digihunch.com:8080;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;proxy_cache_path cache/ keys_zone=auth_cache:10m;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# nifi proxy&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;server {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 8083ssl;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; include /etc/nginx/ssl/default.conf;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; auth_request /auth-proxy;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://nifibackend;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Host $host:$server_port;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-ProxyScheme https;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-ProxyHost $1;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-ProxyPort 8083;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-ProxyContextPath /;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location /auth-proxy {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; internal;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass http://127.0.0.1:8888;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_pass_request_body off;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Content-Length &amp;#34;&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_cache auth_cache;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_cache_valid 200 10m;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_cache_key &amp;#34;$http_authorization$cookie_nginxauth&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Ldap-URL &amp;#34;ldaps://ldap.digihunch.com:636&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Ldap-BaseDN &amp;#34;OU=Corporate User Accounts,DC=digihunch,DC=org&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Ldap-BindDN &amp;#34;CN=Digi Hunch Service Account,OU=Digi,OU=ServiceAccounts,OU=Digi,OU=Digi Applications,DC=digihunch,DC=org&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Ldap-BindPass &amp;#34;myownpasswordtricks&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-CookieName &amp;#34;nginxauth&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header Cookie nginxauth=$cookie_nginxauth;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Ldap_Starttls &amp;#34;true&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; proxy_set_header X-Ldap-Template &amp;#34;(&lt;span style="color:#960050;background-color:#1e0010"&gt;&amp;amp;&lt;/span&gt;(sAMAccountName=%(username)s)(objectClass=organizationalPerson)(memberOf=CN=GH_SYSADMIN,OU=GHCO,OU=Groups,OU=Digi,OU=Digi Applications,DC=digihunch,DC=org))&amp;#34;;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;We need the full distinguished name of bind user to get this to work. Once configured properly, and user attempts to connect through a browser, Nginx will pop up a prompt for username and password. The username will be plugged into the X-Ldap-Template for further queries. The same HTTP header also allows you to filter by membership that the user is associated with.&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/2019/12/networking-basics-3-of-3-common-network-technologies/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Networking Basics 3 of 3 – common network protocols and technologies&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2020/01/several-ways-to-ensure-high-availability/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;High Availability and Load Balancer&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Personal Vim cheatsheet</title><link>https://static.digihunch.com/2019/10/personal-vim-cheatsheet/</link><pubDate>Mon, 07 Oct 2019 17:52:00 -0400</pubDate><guid>https://static.digihunch.com/2019/10/personal-vim-cheatsheet/</guid><description>&lt;p class="wp-block-paragraph"&gt;This is my personal cheatsheet as intermediate Vim user so I skipped the ones that I consider basic. All the commands listed are used in command mode for fast editing.&lt;/p&gt;&#10;&lt;h4 class="wp-block-heading"&gt;Command execution&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In command mode, use colon to start ex command. Here are some examples of ex commands:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;e: edit file&lt;/li&gt;&lt;li&gt;g: global command&lt;/li&gt;&lt;li&gt;q: quit&lt;/li&gt;&lt;li&gt;w: write&lt;/li&gt;&lt;li&gt;s: substitute&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The commands (g)lobal and (s)ubstitute are heavily used in string manipulation. The rest are summarized here:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;:e!&lt;/td&gt;&lt;td&gt;reload current file discarding all unsaved changes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;:e newfile.txt&lt;/td&gt;&lt;td&gt;open file newfile.txt for editing &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;:e .&lt;/td&gt;&lt;td&gt;load current directory&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;:w!&lt;/td&gt;&lt;td&gt;force write (if permission allows)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;shift + zz&lt;/td&gt;&lt;td&gt;equivalent to :wq!&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;shift + zq&lt;/td&gt;&lt;td&gt;equivalent to :q!&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;h4 class="wp-block-heading"&gt;Operator&lt;/h4&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;.&lt;/td&gt;&lt;td&gt;repeat last operation&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;fx&lt;/td&gt;&lt;td&gt;find next character x on the same line&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;h4 class="wp-block-heading"&gt;Text Editing&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;y for yank(copy), i for inside, a for around, d for delete, w for word, p for paragraph or paste. Examples:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;yyp&lt;/td&gt;&lt;td&gt;copy current line and insert after&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;diw&lt;/td&gt;&lt;td&gt;delete the entire word where the cursor sits in (dw deletes from cursor to end of word; db deletes from cursor to beginning of word)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;shift + V&lt;/td&gt;&lt;td&gt;select entire line in visual mode (v selects character in visual mode) &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&amp;gt;&lt;/td&gt;&lt;td&gt;visual mode: indent twice on all selected lines&lt;br&gt;edit mode: indent once for 2 lines&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&amp;lt;&lt;/td&gt;&lt;td&gt;visual mode: outdent three times on all selected lines&lt;br&gt;edit mode: outdent once for 3 lines&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;di&amp;#8221;&lt;/td&gt;&lt;td&gt;delete everything between the double quotes surrounding the cursor (exclusive); use c instead of d to finish the same effect with insert mode&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;di&amp;gt;&lt;/td&gt;&lt;td&gt;delete everything between &amp;lt; and &amp;gt; surrounding the cursor (exclusive); use (c)hange instead of (d)elete to finish the same effect with insert mode&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;dit&lt;/td&gt;&lt;td&gt;delete everything between tags. e.g. &amp;lt;xml&amp;gt;contenttodelete&amp;lt;/xml&amp;gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;dip&lt;/td&gt;&lt;td&gt;delete the entire paragraph&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;da&amp;#8217;&lt;/td&gt;&lt;td&gt;delete everything between the single quote surrounding the cursor (inclusive); use c instead of d to finish the same effect with insert mode&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;da}&lt;/td&gt;&lt;td&gt;delete everything between { and } surrounding the cursor (inclusive); use c instead of d to finish the same effect with insert mode&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;dt.&lt;/td&gt;&lt;td&gt;delete all characters until the next .&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;i&lt;/td&gt;&lt;td&gt;insert at cursor location&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;shift + I&lt;/td&gt;&lt;td&gt;move cursor to first non-blank character of line and start in insert mode&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;a&lt;/td&gt;&lt;td&gt;insert at the location next to cursor&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;shift + A&lt;/td&gt;&lt;td&gt;move cursor to last non-blank character of line and start in insert mode&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;move to beginning of line. ^ moves to first non-blank character in the line. $ moves to the end of line&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Note: wherever d is used in this table, c can be used instead for the same effect but switch to editing mode at the end.&lt;/p&gt;&#10;&lt;h4 class="wp-block-heading"&gt;String Manipulation&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The general patterns are:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;[range]g/pattern/cmd&lt;/li&gt;&lt;li&gt;[range]s/match/replacement/option&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If range is not specified, it applies to current line only! To specify the whole file, use % range. You may also specify line range such as &amp;#8220;10,20&amp;#8221;. Here are some examples: &lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;:%s/bacon/lettuce&lt;/td&gt;&lt;td&gt;For every line of the file, replace the first occurrence of bacon in each line to lettuce&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;:%s/bacon/lettuce/g&lt;/td&gt;&lt;td&gt;For every line of the file, replace all occurrences of bacon to lettuce&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;:s/bacon/lettuce&lt;/td&gt;&lt;td&gt;For current line, replace the first occurrence of bacon to lettuce&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;:s/bacon/lettuce/gi&lt;/td&gt;&lt;td&gt;For current line, replace all occurrences of bacon to lettuce, case insensitive&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;:g/bacon/d&lt;/td&gt;&lt;td&gt;delete all lines that contain pattern &amp;#8216;bacon&amp;#8217;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;:g!/lettuce/d&lt;/td&gt;&lt;td&gt;delete all lines that do not contain pattern &amp;#8216;lettice&amp;#8217;; or use :v/lettuce/d instead&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;:g/^\s*$/d&lt;/td&gt;&lt;td&gt;delete all blank lines. \s* represents zero or more white spaces&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;h4 class="wp-block-heading"&gt;Bookmarking&lt;/h4&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;ma&lt;/td&gt;&lt;td&gt;mark cursor line as bookmark a&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;`a&lt;/td&gt;&lt;td&gt;jump to cursor position at line a&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&amp;#8216;a&lt;/td&gt;&lt;td&gt;jump to beginning of line a&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;`.&lt;/td&gt;&lt;td&gt;jump to last line where change occurred&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&amp;#8220;&lt;/td&gt;&lt;td&gt;jump back &lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;h4 class="wp-block-heading"&gt;Insert Mode&lt;/h4&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Ctrl + N&lt;/td&gt;&lt;td&gt;Auto complete&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;h4 class="wp-block-heading"&gt;Edit and run&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;While tmux and screen can help split screen in Bash, we sometimes need to split a bash screen to run a quick command when we&amp;#8217;re already in vim. This can be done with some simple commands.&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;:term&lt;/td&gt;&lt;td&gt;Open up a terminal above vim. You can also spell :ter or :terminal&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Ctrl+W; Ctrl+W&lt;/td&gt;&lt;td&gt;Press Ctrl+W twice can help you toggle between the terminal and vim buffer&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Ctrl+D&lt;/td&gt;&lt;td&gt;Close the terminal&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This can be very helpful when you are debugging code and need it run repeatedly. You don&amp;#8217;t need to exit vim just to run a command and come back. Note that while you&amp;#8217;re in terminal, you can&amp;#8217;t use Ctrl+W as a shortcut key to backspace a word. Use Alt + Delete instead.&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/2019/09/cryptographic-concepts-for-busy-it-professionals-2-of-2/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Cryptography basics 2 of 2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2019/10/storage-nitty-gritty-4-of-5-backup-and-archive-solutions/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Storage Nitty-Gritty 4 of 5 – Backup and Archive Solutions&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>AWS Certified DevOps Engineer Exam Tips</title><link>https://static.digihunch.com/2019/08/aws-certified-devops-engineer-exam-tips/</link><pubDate>Sat, 17 Aug 2019 23:07:59 -0400</pubDate><guid>https://static.digihunch.com/2019/08/aws-certified-devops-engineer-exam-tips/</guid><description>&lt;p class="wp-block-paragraph"&gt;The last 30 days have been exhausting for me. I studied hard on the new AWS Certified DevOps Engineer exam and thank goodness I passed (750 out of 1000 is required). This was the hardest professional certification I ever worked on. The exam was re-launched recently in March 2019 so there is still a shortage of information around the community. I was hoping to share my experience to help demystify this new exam. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;I had a somewhat solid background to begin with, having taken the AWS Certified Solution Architect Professional exam (before the 2019 update), and worked quite a bit on CloudFormation, automation and Git. However, I still did not anticipate the exam to be this difficult until I was halfway through and already had the exam and materials paid for.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img loading="lazy" decoding="async" width="1469" height="518" src="https://static.digihunch.com/wp-content/uploads/2019/08/image.png" alt="" class="wp-image-127"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Without clear guideline on study material other than the white papers, I first skimmed through the ACloudGuru course, which helped me form a high level sense of exam coverage. Nonetheless it does not cover any topic in-depth and therefore by no means makes an essential part of my study. I checked out &lt;strong&gt;LinuxAcademy course&lt;/strong&gt; and they are much more in-depth for the major topics indeed. I like the course material in Lucid chart. However, the LinuxAcademy course along does not cover everything you need to know.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;What I found extremely helpful is the free training videos from the &lt;a href="https://www.aws.training"&gt;official training website&lt;/a&gt;. I strongly recommend the 7-hour course &lt;strong&gt;Exam Readiness: AWS Certified DevOps Engineer – Professional&lt;/strong&gt;. The instructor did a great job outlining the services and knowledge areas in the assessment . The course also comes with quality sample questions with answers and explanations on what the thinkings are behind the correct answers or why some choices are obviously wrong. I went through these questions twice and feel much better at not only understanding the question, but also understanding the intent of the question.&lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img loading="lazy" decoding="async" width="833" height="156" src="https://static.digihunch.com/wp-content/uploads/2019/08/image-1.png" alt="" class="wp-image-129"/&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Apart from the Exam Readiness course, other &lt;strong&gt;free introductory courses&lt;/strong&gt; from the official training website are helpful as well especially for those services that you only need to know the basics. Most of those courses are 5 ~ 10 minutes long, with brief but sufficient introduction and a demo session. The other extremely helpful resource is the &lt;strong&gt;official practice questions&lt;/strong&gt;. The practice exam is harder than the actual exam but they closely resemble the actual question style in the exam. Unfortunately, no answer is provided but they made me spend time finding answers across the documentations and blogs. It is worth-noting that the AWS blogs provides plenty of use cases that are covered in the questions.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When it comes to the real exam, it covers a lot more topics than its predecessor. Many questions are long and confusing. And I wish I could run a diff command to highlight the differences between choices. During exam preparation you really need to train yourself on reading efficiently. I found myself sometimes eyeball through all four choices at the same time, which get my mind scattered.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;During my study, I divide all services into three categories based on the level of familiarity, and here is my list:&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Category 1. Know these services very well, in and out:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AWS ElasticBeanstalk, OpsWorks Stacks, OpsWorks Chef Automate, CloudFormation, CloudWatch, CodeBuild, CodeCommit, CodeDeploy, CodePipeline, CodeStar, Lambda, API Gateway, Config, Trusted Advisor, CloudTrail, Systems Manager, Autoscaling Group in EC2, DynamoDB&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Category 2. Know these services well, but not necessarily down to every single detail:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Amazon Kinesis Firehose, Kinesis Analytics, Kinesis Streams, Step Functions, Elastic Load Balancer, Secrets Manager, Serverless Application Model (SAM), Route53, RDS, Certificate Manager, ElasticSearch, ECS, ECR&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Category 3. Know about these services at a high level, but do not skip any:&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;AWS Organization, X-Ray, GuardDuty, Macie, Inspector, Service Catalog, KMS, Batch, Athena, Single-Sign-On, Data LifeCycle Manager, CloudSearch, Health Dashboard, Glue, QuickSight, LightSail&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Although I did not mention much about the white papers, I want to highlight their importance again. I would not attempt the exam without reading and understanding the required white papers. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If you aspire to take the AWS certified DevOps Engineer exam I hope this helps you a little bit. Good luck.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&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/2019/07/storage-nitty-gritty-3-of-5-nas-and-object-storage/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Storage Nitty-Gritty 3 of 5 – NAS and Object Storage&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2019/09/cryptographic-concepts-for-busy-it-professionals-2-of-2/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Cryptography basics 2 of 2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Set up automation with Ansible</title><link>https://static.digihunch.com/2019/05/automation-with-ansible-a-primer/</link><pubDate>Wed, 22 May 2019 22:11:00 -0400</pubDate><guid>https://static.digihunch.com/2019/05/automation-with-ansible-a-primer/</guid><description>&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://www.ansible.com/overview/how-ansible-works"&gt;Ansible &lt;/a&gt;is very flexible automation tools with many benefits. The free version is command-line based and here is an example to set it up.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Environment setup&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&lt;li&gt;Ansible 2.8 is required or some command may not work.&lt;/li&gt;&lt;li&gt;Ansible files (including playbooks, tasks and inventory files) are all located in /home/glowing/ansible&lt;/li&gt;&lt;li&gt;Default inventory file needs to be referenced in Ansible configuration /etc/ansible/ansible.cfg. This ensures ansible or ansible-playbook command can pick up hosts or host patterns without requiring inventory file through -i on every execution. Here is what the inventory config looks like in ansible.cfg:&lt;/li&gt;&lt;/ol&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;[defaults]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# some basic default values...&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;inventory = /etc/ansible/hosts,/home/glowing/ansible/inventories/glowing_inventory.yml&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;host_key_checking = False&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ol class="wp-block-list" start="4"&gt;&lt;li&gt;As best practice, servers involved should be able to ssh to each other on RSA key authentication. This can be achieved by adding a separate authorized keys file and reference it from /etc/ssh/sshd_config, at the line starting with AuthorizedKeysFile, and separated with the file name of existing authorized keys with a space. In this way, you may keep public keys of human user in one authorized key file and the public keys of machines in the other.&lt;/li&gt;&lt;li&gt;Build inventory file in ~/ansible/inventories/glowing_inventory.yml. The inventory file can declare some variables to use across hosts. If password is involved (e.g. synchronize module still requires password), it can be stored here with base64 encoded. Here is an example of glowing_inventory.yml&lt;/li&gt;&lt;/ol&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-java" data-lang="java"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;---&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;all:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; vars:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ansible_user: glowing&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; gh_sudo_pass: qGS0bWVuu3Jr&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; gh_dir: &lt;span style="color:#f92672"&gt;/&lt;/span&gt;opt&lt;span style="color:#f92672"&gt;/&lt;/span&gt;glowing&lt;span style="color:#f92672"&gt;/&lt;/span&gt;etc&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tmp_dir: &lt;span style="color:#f92672"&gt;/&lt;/span&gt;tmp&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; children:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dc1_front_end:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hosts:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghfe01:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghfe03:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghfe05:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghfe07:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghfe09:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dc2_front_end:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hosts:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghfe02:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghfe04:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghfe06:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghfe08:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghfe10:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dc1_back_end:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hosts:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghbe01:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghbe03:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghbe05:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dc2_back_end:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hosts:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghbe02:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghbe04:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghbe06:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dc1_database:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hosts:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghdb01:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghdb03:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghdb05:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; dc2_database:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hosts:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghdb02:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghdb04:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; e9a&lt;span style="color:#f92672"&gt;-&lt;/span&gt;ghdb06:&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;That is the basic steps to set up Ansible. Now we can run adhoc commands. The command below allows me to copy a file from executing server to all destination servers that match a pattern:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ansible &amp;#39;dc*_back_end:!&amp;#39;`hostname -s` -e &amp;#34;file_name={{gh_dir}}/test.zip&amp;#34; -m copy -a &amp;#34;src={{file_name}} dest={{file_name}}&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In this command:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;variable {{gh_dir}} is declared in the inventory file. It must be referenced by placing variable name between double curly bracket;&lt;/li&gt;&lt;li&gt;An extra variable {{file_name}} is declared at run time because this is the dynamic part of the command;&lt;/li&gt;&lt;li&gt;This adhoc ansible command uses copy module. With copy module, the src anddest files are in the same absolute path here so we use this variable to save some typing;&lt;/li&gt;&lt;li&gt;reference to the host support wildcard such as dc*_back_end;&lt;/li&gt;&lt;li&gt;&lt;code&gt;hostname -s&lt;/code&gt; returns the host name of the server where the adhoc command is run&lt;/li&gt;&lt;li&gt;:! excluds the running host from being matched as destination server. this is in case that running machine is already in the dc*_back_end group, where copy source and destination are identical&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Here is another example for deleting a file from destination servers:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# ansible dc2_database -e &amp;#34;fn=/tmp/file_to_delete&amp;#34; -m file -a &amp;#34;path={{fn}} state=absent&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;If we can run adhoc command, then we can start writing some playbook and roles. Below is a simple playbook test-conn.yml to ping each server:&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;---&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - name: measure mint retrieval time from {{ ansible_limit }}&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hosts: &amp;#39;{{ ansible_limit }}&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; serial: 1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; order: sorted&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; gather_facts: no&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ignore_errors: yes&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; tasks:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - name: measure time&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; command: curl -s -XGET http://{{ inventory_hostname }}:8080/index.html -o /dev/null&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; delegate_to: localhost&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; register: curlout&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; no_log: true&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - name: display result&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; debug:&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; msg: &amp;#34;Time to load webpage from {{ inventory_hostname }} is {{ curlout.delta }}.&amp;#34;&#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 run that playbook with the following 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;# ansible-playbook -l dc2_front_end test-conn.yml&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Ansible automation is essentially editing yaml files for playbooks. Writing playbook involves a lot of module interaction and one needs to follow best practices. Understanding&lt;a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html"&gt; Ansible roles&lt;/a&gt; can help reuse some code.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In addition here are some common playbook keywords you should be familiar with:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;serial&lt;/li&gt;&lt;li&gt;order&lt;/li&gt;&lt;li&gt;gather_facts&lt;/li&gt;&lt;li&gt;ignore_errors&lt;/li&gt;&lt;li&gt;when&lt;/li&gt;&lt;li&gt;run_once&lt;/li&gt;&lt;li&gt;local_action&lt;/li&gt;&lt;li&gt;register&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Here are common modules to know&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;set_fact&lt;/li&gt;&lt;li&gt;state&lt;/li&gt;&lt;li&gt;touch&lt;/li&gt;&lt;li&gt;fail&lt;/li&gt;&lt;li&gt;synchoronize&lt;/li&gt;&lt;li&gt;lineinfile&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&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/2019/05/storage-nitty-gritty-2-5/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Storage Nitty-Gritty 2 of 5 – SAN&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2019/06/git-explained-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;Git Explained 1 of 2&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Package Repository Management for Linux</title><link>https://static.digihunch.com/2019/02/package-repository-management-in-linux/</link><pubDate>Sat, 09 Feb 2019 22:14:56 -0400</pubDate><guid>https://static.digihunch.com/2019/02/package-repository-management-in-linux/</guid><description>&lt;p class="wp-block-paragraph"&gt;RPM is the package manager tool in Linux. YUM is a repository management tool to fetch appropriate package for the particular version of Linux. YUM performs automatic dependency resolution when updating, installing or removing packages, and thus is able to automatically determine, fetch and install all available dependent packages. This posting is about common commands used for package management. Then we walk through the step to set up a local yum repository. Lastly, we summarize the best practice for patch management.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Tools&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In addition to the basic yum install, update and remove commands, here are some more tools for repository management:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## check for installed packages with updates available&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum check-update&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## search for packages&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum search package.name&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## check for dependency&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum deplist package.name&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## list installed or available packages:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum list installed package.name&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum list available package.name&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## list all available packages of a repo:&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum --disablerepo&lt;span style="color:#f92672"&gt;=&lt;/span&gt;* --enablerepo&lt;span style="color:#f92672"&gt;=&lt;/span&gt;repo.name list available&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## display package info&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum info package.name&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## list all repositories&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum repolist&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum repoinfo&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## list all transactions&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum history list all&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## display history of a package or transaction id&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum history package-list package.name&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum history info package.name&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum history info transaction.id&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;## undo or redo a transaction&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum history undo transaction.id&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum history redo transaction.id&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;RHEL provides a more complete &lt;a href="https://access.redhat.com/sites/default/files/attachments/rh_yum_cheatsheet_1214_jcs_print-1.pdf"&gt;cheatsheet&lt;/a&gt; for yum commands.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In addition to single package, YUM also manages &lt;a href="https://access.redhat.com/solutions/15815"&gt;package groups&lt;/a&gt;, and works with &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/6/html/deployment_guide/sec-yum_plugins"&gt;plugins&lt;/a&gt;. For example, you may enable security related packages only by using the &lt;a href="https://access.redhat.com/solutions/10021"&gt;yum-plugin-security&lt;/a&gt;. For security, YUM repositories can enable GPG check (based on public key cryptography).&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Local Repo configuration&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Now we configure a YUM repository server and reference that from a client to update packages. To begin with, we collect all RPM packages in /home/dhunch/upgrade/downloads/, then we install createrepo package and use it to create metadata:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum install createrepo yum-utils&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;createrepo /home/dhunch/upgrade/downloads/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Examine the directory and you will find a new repodata directory created. Now we can configure nginx with the following configuration:&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;server {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; listen 8088;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; server_name rpmsource.digihunch.com;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; root /home/dhunch/upgrade/downloads/;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; location / {&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; autoindex on; #enable listing of directory index&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;}&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Restart nginx and browse to server name at port 8088, you should see the directory in html. If you&amp;#8217;re getting 403 error, most likely nginx has issues accessing the directory. Nginx process should be able to traverse each level of directory to serve the files. The parent directories should have executable permission for others. For example:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chmod o+x /home/dhunch/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Here is a reference to &lt;a href="https://www.digitalocean.com/community/questions/proper-permissions-for-web-server-s-directory"&gt;nginx permission&lt;/a&gt; requirement. Now we can continue to configure the client.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On the client, we need to add a file in /etc/repos.d/yum&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;[digirepo]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;name=Local YUM Repository &#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;baseurl=http://rpmsource.digihunch.com:8088/&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;enabled=1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;gpgcheck=0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Last we can check the available packages from the client:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;yum --disablerepo&lt;span style="color:#f92672"&gt;=&lt;/span&gt;* --enablerepo&lt;span style="color:#f92672"&gt;=&lt;/span&gt;digirepo list available&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Note that in order to keep the local repo up-to-date, there is additional maintenance work on the server. You may need to sync from official source, such as:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;reposync -g -l -d -m --repoid&lt;span style="color:#f92672"&gt;=&lt;/span&gt;base-source --newest-only --download-metadata --download_path&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/home/dhunch/upgrade/downloads/&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;You may also need to set up a daily job with &lt;a href="https://www.redhat.com/sysadmin/using-yum-cron"&gt;yum-cron&lt;/a&gt; service so this is automated.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Sometimes the server is locked down and you need HTTP proxy to allow YUM to access repo. You may configure proxy in /etc/yum.conf in the proxy, proxy_username, and proxy_password entries. Also, you may export environment variable http_proxy. &lt;a href="https://www.rosehosting.com/blog/how-to-enable-proxy-settings-for-yum-command-on-centos-7/" class="rank-math-link"&gt;Here&lt;/a&gt; are more information.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Sometimes yum cache may introduce issues. To clean cache before installing, run:&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;yum clean all &amp;amp;amp;&amp;amp;amp; yum -y install python3&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 class="wp-block-heading"&gt;Python packages&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Python3 is not installed by default on CentOS 7. So it needs to be installed with YUM. Do not replace the existing python2 with python3 by changing where symbolic link /bin/python points to, because YUM is dependent on python2.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;For python3 use pip3 as package management. If the server does not have a public route, then you need to install pip3 package offline. For example, on a server with Internet, run&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pip3 download -d ~/Downloads javaobj-py3&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then SCP the file to the offline server (e.g. to /home/dhunch/javaobj/), from which you can run:&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;pip3 install --no-index --find-links=/home/dhunch/javaobj/ javaobj-py3 --user&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This will install the pip3 package offline. Note it is recommended to not run pip3 installer as root user. The switch &amp;#8211;user allows you to run as non-root user.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Best Practices&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To configure a patch management environment, we assume that the servers do not have access to the Internet, not even through proxy. This should be part of the security guideline anyways. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;This requires a local repository server to be setup. Administrators may use createrepo tool as outline above to create such repo, use reposync to synchronize local source from official source, or yum-cron to automate this for daily task.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On the clients, administrators should manage the repo file in /etc/yum.repo.d, to ensure they are pointing to the correct source, using gpg check, etc. A local script to enable and disable different repos are also helpful. Otherwise, the enabelrepo and disablerepo switch can be used per command.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;It is important to catalogue the state of operating system, before and after each patching activity, for verification and auditing purposes. This usually requires scripting work using yum history or package-cleanup tools.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The actual patch work can be done either manually or automatically (e.g. with Ansible&amp;#8217;s yum module). RPM is also a good tool for troubleshooting. If the scope of patching is only for security, use the yum-plugin-security to limit the packages to only security related ones.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Roll-back should be prepared in case of inadvertent outcome. Roll-back scripting relies heavily on yum history commands. If the OS needs to boot with a previous kernel, use the grubby tool.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Happy Patching!&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/2019/01/interesting-terms-about-unsuccessful-software-project-management/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Interesting terms and principles&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2019/03/storage-nitty-gritty-1-5/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Storage Nitty-Gritty 1 of 5 – Disk and RAID&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Redhat Firewall configuration: from iptables to firewalld</title><link>https://static.digihunch.com/2018/10/redhat-firewall-configuration-firewalld-vs-iptables/</link><pubDate>Fri, 12 Oct 2018 17:56:00 -0400</pubDate><guid>https://static.digihunch.com/2018/10/redhat-firewall-configuration-firewalld-vs-iptables/</guid><description>&lt;h3 class="wp-block-heading"&gt;Tools to manage firewall&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Packet filter rules in Linux Kernel is managed by an user-space application named iptables in CentOS and RedHat. Since CentOS 7, &lt;a href="https://en.wikipedia.org/wiki/Firewalld"&gt;firewalld&lt;/a&gt; is introduced as an alternative to iptables. Firewalld can be installed and executed as a systemd service, and it is supposed to replace iptables. This &lt;a href="https://www.tecmint.com/firewalld-vs-iptables-and-control-network-traffic-in-firewall/"&gt;article&lt;/a&gt; describes how to configure both. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;There are several advantages in firewalld. One is is the support of &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/sec-using_zones_to_manage_incoming_traffic_depending_on_source"&gt;zones&lt;/a&gt;. &lt;a href="https://www.digitalocean.com/community/tutorials/how-to-set-up-a-firewall-using-firewalld-on-centos-7"&gt;Here&lt;/a&gt; are some useful information. Also, iptables involves three different services for IPv4(iptables), IPv6(ip6tables), and software bridging (ebtables), whereas firewalld only involves a single service to manage all three. Firewalld allows user to add or remove rules/ports from running firewall, without restarting firewall. Unless you have specific reason to use iptables, always use firewalld service to manage firewall. Here is an instruction to firewalld service. In this posting however, we will be focusing on iptables to understand firewall managment. We also go through an example of opening a TCP port. &lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;How does iptables work&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When working with iptables, it is important to understand that its related concepts (&lt;strong&gt;tables-&amp;gt;chains-&amp;gt;rules-&amp;gt;criteria and targets&lt;/strong&gt;) and how the &lt;strong&gt;order of rules&lt;/strong&gt; plays a factor. There are five independent &lt;strong&gt;&lt;span style="text-decoration: underline;"&gt;tables&lt;/span&gt;&lt;/strong&gt;, each contains a number of &lt;strong&gt;&lt;span style="text-decoration: underline;"&gt;chains&lt;/span&gt;&lt;/strong&gt;, either &lt;em&gt;built-in&lt;/em&gt; or &lt;em&gt;user-defined&lt;/em&gt;. Administrators mostly deals with &lt;em&gt;&lt;span style="text-decoration: underline;"&gt;built-in chains&lt;/span&gt;&lt;/em&gt; in &lt;em&gt;&lt;span style="text-decoration: underline;"&gt;filter&lt;/span&gt;&lt;/em&gt; and &lt;em&gt;&lt;span style="text-decoration: underline;"&gt;nat&lt;/span&gt;&lt;/em&gt; tables. The five tables are:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;&lt;strong&gt;filter&lt;/strong&gt;: If -t isn&amp;#8217;t specified, this is the default table. It contains built-in chains:&lt;ul&gt;&lt;li&gt;&lt;strong&gt;INPUT&lt;/strong&gt;: for packet destined to local sockets&lt;/li&gt;&lt;li&gt;&lt;strong&gt;FORWARD&lt;/strong&gt;: for packets being routed through the box&lt;/li&gt;&lt;li&gt;&lt;strong&gt;OUTPUT&lt;/strong&gt;: for locally-generated packets&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;nat&lt;/strong&gt;: this table is consulted when a packet that creates a new connection is encountered. It has three built-in chains:&lt;ul&gt;&lt;li&gt;&lt;strong&gt;PREROUTING&lt;/strong&gt;: for altering packets as soon as they come in&lt;/li&gt;&lt;li&gt;&lt;strong&gt;OUTPUT&lt;/strong&gt;: for altering locally generated packets before routing&lt;/li&gt;&lt;li&gt;&lt;strong&gt;POSTROUTING&lt;/strong&gt;: for altering packets as they are about to go out&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;mangle&lt;/strong&gt;: this table is used for specialized packet alternation, with five built-in chains (since kernel 2.4.18): PREROUTING and OUTPUT, INPUT, FORWARD, and POSTROUTING&lt;/li&gt;&lt;li&gt;&lt;strong&gt;raw&lt;/strong&gt;: this table is mainly for configuring exceptions from connection tracking with two built-in chains: PREROUTING and OUTPUT&lt;/li&gt;&lt;li&gt;&lt;strong&gt;security&lt;/strong&gt;: for Mandatory Access Control (MAC) networking rules, with three built-in chains: INPUT, OUTPUT, and FORWARD.&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Under the table (e.g. filter, nat), each chain (e.g. INPUT, OUTPUT, etc) consists of list of &lt;span style="text-decoration: underline;"&gt;&lt;strong&gt;firewall rules&lt;/strong&gt;&lt;/span&gt;. Each rule is made up of two parts defined for the packets:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;&lt;strong&gt;Criteria&lt;/strong&gt;: if the packet does not match the criteria, the next rule in the chain is examined; if it does match, then the next rule is specified by the value of the target.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Target&lt;/strong&gt;: what to do if criteria is met. The target can be:&lt;ul&gt;&lt;li&gt;user-defined chain, &lt;/li&gt;&lt;li&gt;one of the target described in iptables-extensions, or &lt;/li&gt;&lt;li&gt;in most cases, one of the special values ACCEPT, DROP or RETURN&lt;ul&gt;&lt;li&gt;&lt;strong&gt;ACCEPT&lt;/strong&gt; &amp;#8211; let the packet through&lt;/li&gt;&lt;li&gt;&lt;strong&gt;DROP&lt;/strong&gt; &amp;#8211; drop the packet on the floor&lt;/li&gt;&lt;li&gt;&lt;strong&gt;RETURN&lt;/strong&gt; &amp;#8211; stop traversing this chain, and resume at &lt;span style="text-decoration: underline;"&gt;next rule in the previous (calling) chain&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The rules, defined in each chain under their tables, can be found in file /etc/sysconfig/iptables. You can find tables (prefix with asterisk *), chains (prefix with colon :), rules under their chains and a statement COMMIT after each table. The iptables process flow illustrates how a packet interact with all these rules under different chains and tables defined in this file: &lt;/p&gt;&#10;&lt;figure class="wp-block-image"&gt;&lt;img decoding="async" src="https://miro.medium.com/max/1000/1*OIoNQkH4RTSm-eY2lUMBcQ.jpeg" alt="IPTables and Docker. In this post I will be talking about… | by Edouard Buschini | Medium"/&gt;&lt;figcaption&gt;iptables Process Flow&lt;/figcaption&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Although this big picture looks formidable, an administrator commonly only deals with the green and purple blocks (filter and nat), with the big picture in mind. Here is an example of /etc/sysconfig/iptables file from a newly installed system:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Generated by iptables-save v1.4.21 on Fri Sep 11 23:15:32 2017&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;*filter&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:INPUT ACCEPT &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0:0&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:FORWARD ACCEPT &lt;span style="color:#f92672"&gt;[&lt;/span&gt;0:0&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:OUTPUT ACCEPT &lt;span style="color:#f92672"&gt;[&lt;/span&gt;132:17200&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p icmp -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -i lo -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p tcp -m state --state NEW -m tcp --dport &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -j REJECT --reject-with icmp-host-prohibited&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A FORWARD -j REJECT --reject-with icmp-host-prohibited&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;COMMIT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# Completed on Fri Sep 11 23:15:32 2017&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The rule simply allows SSH traffic. This file will be loaded up on every reboot (specifically, restart of iptables service). So if you have made some changes to rules and you want the change picked up on reboot. The rules should be saved to this file:&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;$ sudo iptables-save &amp;gt; /etc/sysconfig/iptables&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Other than saving rule for reboot, if you simply want to edit the rules (e.g. order of rules is incorrect), you can save the rules to file, modify the file and restore the rule from file:&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;$ sudo iptables-save &amp;gt; ~/iptables.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo vi ~/iptables.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ sudo iptables-restore &amp;amp;lt; ~/iptables.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;&lt;a href="https://www.digitalocean.com/community/tutorials/a-deep-dive-into-iptables-and-netfilter-architecture"&gt;Here&lt;/a&gt; is some further reading about iptables architecture.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Anatomy of a rule&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The man page for iptables species the following synopsis:&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;iptables [-t table] {-A|-C|-D} chain rule-specification&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;rule-specification = [matches...] [target]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;match = -m matchname [per-match-options]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;target = -j targetname [per-target-options]&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;So when you append (-A), delete (-D), insert (-I) or replace (-R) a rule, you need to specify rule specification. The man page further explains that the following parameters make up a rule specification:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;&lt;strong&gt;protocol (-p)&lt;/strong&gt;: the protocol of the rule of the packet to check. value can be tcp, udp, icmp, all or any name defined in /etc/protocols.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;match (-m)&lt;/strong&gt;: specifies the name of a match to use and is followed by match options. The match refers to an extension module that tests for a specific property. Those extension modules are documented in the man page of &lt;a href="https://ipset.netfilter.org/iptables-extensions.man.html"&gt;iptables-extensions&lt;/a&gt;. You may specify -m multiple times for different match names, which together make up the condition under which a target is invoked. Matches are evaluated first to last as specified. We often use extensions &lt;em&gt;tcp&lt;/em&gt; and &lt;em&gt;state&lt;/em&gt;. According to iptables-extensions man page, we can specify &amp;#8211;dport followed by port number for the &lt;em&gt;tcp&lt;/em&gt; extension, and &amp;#8211;state followed by value such as NEW or ESTABLISHED for the &lt;em&gt;state&lt;/em&gt; extension.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;jump (-j)&lt;/strong&gt;: specifies the target of the rule, such as ACCEPT, REJECT or DROP.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;source and destination (-s and -d)&lt;/strong&gt;: source and destination IP address or masks. Hostname will work but not recommended since resolution is needed.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;inbound and outbound interface (-i and -o)&lt;/strong&gt;: name of interface via which the packet was received and is going to be sent.&lt;/li&gt;&lt;li&gt;&lt;strong&gt;goto (-g)&lt;/strong&gt;: processing should continue in a user specified chain&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Other&lt;/strong&gt; parameters: -4/&amp;#8211;ipv4, -6/&amp;#8211;ipv6, -c/&amp;#8211;set-counters, -f/&amp;#8211;fragment&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;When we run iptables command to view rules, we need to specify the table (e.g. filter, nat, etc) followed by -S or &amp;#8211;list-rules:&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;$ iptables -t nat -S&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;If you do not specify -t switch, the default (-t filter) is applied. Be aware that in this case, you&amp;#8217;re only seeing rules under filter table, and not all rules under tall tables!&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In the result, for example one line from command &amp;#8220;iptables -S&amp;#8221; may say:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p tcp -m state --state NEW -m tcp --dport &lt;span style="color:#ae81ff"&gt;9200&lt;/span&gt; -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;The interpretation: appending a rule to INPUT chain of filter table (implicitly specified). The protocol is tcp. The first match extension is state, and the state value shall be NEW. The second match extension is tcp, and the dport value shall be 9200. If the packet is a match, then the target (action) is ACCEPT.&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Managing rules&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;As mentioned earlier, rules can be dumped to any file or /etc/sysconfig/iptables, in which the rules are assessed in order. Below is a real life iptables file with a nat table as well. &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;# Generated by iptables-save v1.4.21 on Wed Jan 15 13:58:39 2017&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;*filter&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:INPUT DROP [0:0]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:FORWARD DROP [0:0]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:OUTPUT ACCEPT [4:208]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p icmp -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -i lo -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -s 10.100.160.56/32 -p tcp -m state --state NEW -m tcp --dport 7000:7001 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -s 10.100.160.56/32 -p tcp -m state --state NEW -m tcp --dport 7199 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -s 10.100.160.56/32 -p tcp -m state --state NEW -m tcp --dport 9042 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -s 10.100.160.56/32 -p tcp -m state --state NEW -m tcp --dport 9160 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p tcp -m state --state NEW -m tcp --dport 8080 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p udp -m state --state NEW -m udp --dport 161 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p udp -m state --state NEW -m udp --dport 162 -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -j REJECT --reject-with icmp-host-prohibited&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A FORWARD -j REJECT --reject-with icmp-host-prohibited&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;COMMIT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;*nat&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:PREROUTING ACCEPT [1:328]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:INPUT ACCEPT [0:0]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:OUTPUT ACCEPT [0:0]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;:POSTROUTING ACCEPT [0:0]&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A PREROUTING -p tcp -m tcp --dport 2392 -j REDIRECT --to-ports 2398&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A PREROUTING -p tcp -m tcp --dport 2393 -j REDIRECT --to-ports 2398&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A OUTPUT -o lo -p tcp -m tcp --dport 2392 -j REDIRECT --to-ports 2398&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A OUTPUT -o lo -p tcp -m tcp --dport 2393 -j REDIRECT --to-ports 2398&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;COMMIT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;# Completed on Wed Jan 15 13:58:39 2017&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;In this example, the nat table defines traffic forwarding: traffic arriving at TCP port 2392 and 2393 are forwarded to port 2398; outgoing traffic to port 2392 and 2393 are also redirected to port 2398. These rules do not overlap each other so the rules probably don&amp;#8217;t matter.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On the other hand, the tcp filter table lists the rules to open certain TCP and UDP ports. Its block starts with a couple accepting rules and ends with a couple reject rules (regardless of protocols or ports). This is a good way to close a chain of rules with security. However, if you need to add additional rules to open more TCP ports, the new rule should not be appended after the reject rules at the bottom since the order matter here!&lt;/p&gt;&#10;&lt;h3 class="wp-block-heading"&gt;Correct way to open a TCP port&lt;/h3&gt;&#10;&lt;p class="wp-block-paragraph"&gt;It&amp;#8217;s a common task for developers to open a TCP port simply for the purpose of bring up a web service and make it accessible to client. If we simply add a new rule to existing list, for example:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# iptables -A INPUT -m state --state NEW -m tcp -p tcp --dport 9870 -j ACCEPT&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# iptables -S&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-P INPUT ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-P FORWARD ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-P OUTPUT ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p icmp -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -i lo -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p tcp -m state --state NEW -m tcp --dport &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -j REJECT --reject-with icmp-host-prohibited&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p tcp -m state --state NEW -m tcp --dport &lt;span style="color:#ae81ff"&gt;9870&lt;/span&gt; -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A FORWARD -j REJECT --reject-with icmp-host-prohibited&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# systemctl reload iptables&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;You will notice that the rule is appended to the end of INPUT block, below the INPUT REJECT rule, which will never take effect.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To address this, you can use iptables-save and iptables-restore to export, edit to correct order and reload the rule, as illustrated above, instead of using iptables command to modify the rule directly. &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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# iptables-save &amp;gt; /tmp/rule.list&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# vi /tmp/rule.list&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# iptables-restore &amp;lt; /tmp/rule.list&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# iptables -S&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-P INPUT ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-P FORWARD ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-P OUTPUT ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p icmp -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -i lo -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p tcp -m state --state NEW -m tcp --dport &lt;span style="color:#ae81ff"&gt;22&lt;/span&gt; -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -p tcp -m state --state NEW -m tcp --dport &lt;span style="color:#ae81ff"&gt;9870&lt;/span&gt; -j ACCEPT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A INPUT -j REJECT --reject-with icmp-host-prohibited&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;-A FORWARD -j REJECT --reject-with icmp-host-prohibited&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Alternatively, you could use some advanced iptables command switches to add the new rule to certain line number with &amp;#8211;line-number switch. &lt;a href="https://www.osetc.com/en/linux-iptables-insert-rule-at-a-specific-position-prepend-firewall-rule.html"&gt;Here&lt;/a&gt; is more information.&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/2018/09/log-shipping-through-elk/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Log shipping through ELK&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2018/11/the-java-confusions/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Java version confusions&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Linux Admin Basics 3 of 3 – text processing, regex, sed &amp; awk</title><link>https://static.digihunch.com/2018/06/text-processing-with-linux-bash/</link><pubDate>Wed, 06 Jun 2018 19:56:00 -0400</pubDate><guid>https://static.digihunch.com/2018/06/text-processing-with-linux-bash/</guid><description>&lt;p class="wp-block-paragraph"&gt;Most of the text processing can be processed by awk and sed. Sed is non-interactive stream editor that allows you to specify all editing instructions in one place and execute them on a single pass through the file. Awk is a pattern-matching programming language.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Using sed and awk requires some understanding of regular expressions. Here&amp;#8217;s the basics of regular expression signs:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;sign&lt;/td&gt;&lt;td&gt;operation&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;^&lt;/td&gt;&lt;td&gt;matches beginning of line&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;$&lt;/td&gt;&lt;td&gt;matches end of line&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;.&lt;/td&gt;&lt;td&gt;matches any single character (wildcard)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;*&lt;/td&gt;&lt;td&gt;repeat previous token zero, one or more times.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;+&lt;/td&gt;&lt;td&gt;repeat previous token one or more times&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;?&lt;/td&gt;&lt;td&gt;repeat previous token zero or one time&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[&amp;#8230;]&lt;/td&gt;&lt;td&gt;matches any one of the class of characters enclosed between the classes.&lt;br&gt; ^ as first character reverses the match&lt;br&gt; &amp;#8211; is used to ndicate a range of characters&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;()&lt;/td&gt;&lt;td&gt;groups regex &lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;|&lt;/td&gt;&lt;td&gt;either preceding or following regex can be matched&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;{n,m}&lt;/td&gt;&lt;td&gt;matches a range of occurrences of the single character that immediately precedes it. &lt;br&gt; {n} will match exactly n occurrences&lt;br&gt; {n,} will match at least n occurrences&lt;br&gt; {n,m} will match any number of occurrences between n and m&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Common expressions&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-regular"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;exp&lt;/td&gt;&lt;td&gt;interpretation&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[^0-9]&lt;/td&gt;&lt;td&gt;excluding number&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;[15]00*&lt;/td&gt;&lt;td&gt;matches &amp;#8220;10&amp;#8221;, &amp;#8220;50&amp;#8221;, &amp;#8220;100&amp;#8221;, &amp;#8220;500&amp;#8221;, &amp;#8220;1000&amp;#8221;, &amp;#8220;5000&amp;#8221;. Here the first 0 is literal, the second is modified by *, see the table above&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;.*&lt;/td&gt;&lt;td&gt;any number (including 0) of any character&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&amp;lt;.*&amp;gt;&lt;/td&gt;&lt;td&gt;any html tags&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt; book &lt;/td&gt;&lt;td&gt;matches book with preceding and following spaces&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt; books* &lt;/td&gt;&lt;td&gt;matches books, or book, but not &amp;#8220;book.&amp;#8221; &amp;#8220;book?&amp;#8221; etc&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt; book.* &lt;/td&gt;&lt;td&gt;matches book, followed by any number of characters, or none followed by a space&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Note that regular expression comes in several different flavours, which can be confusing and frustrating. &lt;a href="https://unix.stackexchange.com/questions/119905/why-does-my-regular-expression-work-in-x-but-not-in-y" class="rank-math-link"&gt;This&lt;/a&gt; is a good summary. There are DFA (Deterministic Finite Automata) based engines and NFA (Non-Deterministic Finite Automata) based engines:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;NFA based engines can &amp;#8220;go back&amp;#8221; in the regex, used in Perl, Python, vim, sed and GNU grep.&lt;/li&gt;&lt;li&gt;DFA based engines cannot &amp;#8220;go back&amp;#8221; in the regex, used in awk and BSD grep. &lt;/li&gt;&lt;/ul&gt;&#10;&lt;figure class="wp-block-table"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Standard&lt;/td&gt;&lt;td&gt;IEEE POSIX&lt;br&gt;BRE&lt;/td&gt;&lt;td&gt;IEEE POSIX&lt;br&gt;ERE&lt;/td&gt;&lt;td&gt;PCRE&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Detail&lt;/td&gt;&lt;td&gt;Basic Regular Expressions&lt;/td&gt;&lt;td&gt;Extended Regular Expressions that add repetition, alternation on top of BRE&lt;/td&gt;&lt;td&gt;Perl Compatible regular expression.&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Engine&lt;/td&gt;&lt;td&gt;DFA&lt;/td&gt;&lt;td&gt;DFA&lt;/td&gt;&lt;td&gt;NFA&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GNU grep&lt;/td&gt;&lt;td&gt;grep by default, or grep -G&lt;/td&gt;&lt;td&gt;egrep&lt;br&gt;grep -E&lt;/td&gt;&lt;td&gt;grep -P&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BSD grep&lt;/td&gt;&lt;td&gt;grep&lt;/td&gt;&lt;td&gt;egrep&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;GNU sed&lt;/td&gt;&lt;td&gt;sed&lt;/td&gt;&lt;td&gt;sed -r&lt;/td&gt;&lt;td&gt;NA. Just use perl&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;BSD sed&lt;/td&gt;&lt;td&gt;sed&lt;/td&gt;&lt;td&gt;sed -E&lt;/td&gt;&lt;td&gt;NA. Just use perl&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;awk&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;awk&lt;/td&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The best way to check isn on &lt;a href="https://www.freebsd.org/cgi/man.cgi" class="rank-math-link"&gt;BSD&lt;/a&gt; manual and &lt;a href="https://www.gnu.org/software/" class="rank-math-link"&gt;GNU&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Here are several examples of sed and awk I came across at work:&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Find and remove duplicate lines:&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;awk &amp;#39;!x[$0]++&amp;#39; input_file.txt &amp;gt; output_file.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Remove white spaces at the beginning and end of each line:&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;awk &amp;#39;{$1=$1}1&amp;#39; input_file.txt &amp;gt; output_file.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Print with multiple dilimiters (;, , , and |)&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;awk -F &amp;#39;[;,|]&amp;#39; &amp;#39;{print $1, $3, $5}&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Print with calculation between columns&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;awk &amp;#39;{res=$1-$2;print res,$0}&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Print rows conditionally&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;awk &amp;#39;$1&amp;gt;20{print;}&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Prefix each line of a file&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;awk &amp;#39;$0=&amp;#34;PREFIX|&amp;#34;$0&amp;#39; input.txt &amp;gt; prefix.input.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Replace string original to new in file&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;sed -i &amp;#39;s/original/new/g&amp;#39; file.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Remove multiple patterns&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;sed &amp;#39;s/pattern1\|pattern2\|pattern3//g&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Delete the first matching pattern only&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;sed &amp;#39;s/pattern//&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Remove blank lines:&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;sed -i &amp;#39;/^$/d&amp;#39; input_file.txt &amp;gt; output_file.txt&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Copy from line 100 to line 500 of input file to output file&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;sed -n 100,500p input.log&amp;gt;output.log&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Merge every three lines:&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;sed &amp;#39;N;N;N; s/\n/ /g&amp;#39;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;nav class="wp-post-navigation" aria-label="Post navigation"&gt;&#10;&lt;a rel="prev" href="https://static.digihunch.com/2018/05/cron-and-logrotate-in-centos/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;cron and anacron in RedHat Linux (How logrotate works)&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2018/06/dicom-data-encoding/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;DICOM data encoding&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>cron and anacron in RedHat Linux (How logrotate works)</title><link>https://static.digihunch.com/2018/05/cron-and-logrotate-in-centos/</link><pubDate>Tue, 15 May 2018 14:11:00 -0400</pubDate><guid>https://static.digihunch.com/2018/05/cron-and-logrotate-in-centos/</guid><description>&lt;h4 class="wp-block-heading"&gt;Cron and anacron&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;We all know cron is a job scheduler. Many admin uses crontab to manage scheduled task. It is also important to know that crontab works at different levels as well, as well as the distinction between cron and anacron. They are similar, but different, managed by different sets of files. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Below is a brief description of how cron works from this &lt;a href="https://www.sitepoint.com/a-comprehensive-crash-course-into-cronjobs/"&gt;article&lt;/a&gt;.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;After Cron starts, it searches its spool area to find and load crontab files into the memory. It additionally checks the /etc/crontab and or /etc/cron.d directories for system crontabs.&lt;br&gt;After loading the crontabs into memory, Cron checks the loaded crontabs on a minute-by-minute basis, running the events which are due.&lt;br&gt;In addition to this, Cron regularly (every minute) checks if the spool directory’s modtime (modification time) has changed. If so, it checks the modetime of all the loaded crontabs and reloads those which have changed. That’s why we don’t have to restart the daemon when installing a new cron job.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Basically, in cron, you specify a particular time at which a job will run. These jobs are managed by files in &lt;em&gt;/var/spool/cron/ &lt;/em&gt;directory. In this directory, each file is named by the username that owns the crontab file. These files shall not be edited directly by respective users. Instead, they are edited by crontab by each user. To understand the syntax, one can refer to RedHat document for &lt;a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/system_administrators_guide/ch-Automating_System_Tasks"&gt;automating system tasks&lt;/a&gt;. Note that you can specify periodical jobs here with special syntax. For example, */5 at the minute slot indicates every five minutes.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Running cron jobs can be allowed or disallowed for different users. For this purpose, use the &lt;em&gt;/etc/cron.allow&lt;/em&gt; and &lt;em&gt;/etc/cron.deny&lt;/em&gt; files. If the cron.allow file exists, a user must be listed in it to be allowed to use cron If the cron.allow file does not exist but the cron.deny file does exist, then a user must not be listed in the cron.deny file in order to use cron. If neither of these files exists, only the super user is allowed to use cron.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In addition, there is a system-wide crontab file in /etc/crontab, in which you need to not only specify tasks, but also the user to run those tasks. By default, the schedule in this file is empty.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The limitation of cron is it assumes the servers is up all the time, if a script misses the schedule while the server is down, it will not be executed when the server comes back up. This is where anacron comes in handy. Although anacron can only be used by superuser, it doesn&amp;#8217;t expect system to be running 24&amp;#215;7. If a job is scheduled at a time system is down, it starts the job when system comes back up. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Both cron and anacron are run by systemd service named crond.service. Although they require different packages installed (cronie vs cronie-anacron). They are also managed by different sets of files as explained below:&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&#10;&lt;table id="tablepress-4" class="tablepress tablepress-id-4 tbody-has-connected-cells"&gt;&#10;&lt;thead&gt;&#10;&lt;tr class="row-1"&gt;&#10;&#9;&lt;th class="column-1"&gt;package&lt;/th&gt;&lt;th class="column-2"&gt;file or directory&lt;/th&gt;&lt;th class="column-3"&gt;purpose&lt;/th&gt;&lt;th class="column-4"&gt;example&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody class="row-striping row-hover"&gt;&#10;&lt;tr class="row-2"&gt;&#10;&#9;&lt;td rowspan="2" class="column-1"&gt;cronie&lt;/td&gt;&lt;td class="column-2"&gt;/var/spool/cron/&lt;/td&gt;&lt;td class="column-3"&gt;this directory accommodates files that represents cron jobs for each individual users.&lt;/td&gt;&lt;td class="column-4"&gt;if a file named digihunch contains a valid line, it means that Linux user digihunch has a scheduled task for the time specified.&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-3"&gt;&#10;&#9;&lt;td class="column-2"&gt;/etc/crontab&lt;/td&gt;&lt;td class="column-3"&gt;This file keeps system-wide cronjob entries. Each line needs to sepcify users.&lt;/td&gt;&lt;td class="column-4"&gt;if a line specifies schedule, user and command, it means that at the scheduled time, that user will execute the command.&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-4"&gt;&#10;&#9;&lt;td rowspan="3" class="column-1"&gt;cronie-anacron&lt;/td&gt;&lt;td class="column-2"&gt;/var/spool/anacron/&lt;/td&gt;&lt;td class="column-3"&gt;This directory accommodates files such as cron.daily, in which a timestamp is kept to indicate last execution time.&lt;/td&gt;&lt;td class="column-4"&gt;if cron.daily in this directory reads 20180418, it indicates last daily execution time stamp is 20180418&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-5"&gt;&#10;&#9;&lt;td class="column-2"&gt;/etc/anacrontab&lt;/td&gt;&lt;td class="column-3"&gt;This file tells anacron where in the file system to go for directories for periodical jobs.&lt;/td&gt;&lt;td class="column-4"&gt;Example:&lt;br /&gt;&#10;&lt;code&gt;&lt;br /&gt;&#10;#period in days delay in minutes job-identifier command&lt;br /&gt;&#10;1 5 cron.daily nice run-parts /etc/cron.daily&lt;br /&gt;&#10;7 25 cron.weekly nice run-parts /etc/cron.weekly&lt;br /&gt;&#10;@monthly 45 cron.monthly nice run-parts /etc/cron.monthly&lt;br /&gt;&#10;&lt;/code&gt;&lt;br /&gt;&#10;The file usually also indicates RANDOM_DELAY and START_HOURS_RANGE&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr class="row-6"&gt;&#10;&#9;&lt;td class="column-2"&gt;/etc/cron.hourly/&lt;br /&gt;&#10;/etc/cron.daily/&lt;br /&gt;&#10;/etc/cron.weekly/&lt;br /&gt;&#10;/etc/cron.monthly/&lt;/td&gt;&lt;td class="column-3"&gt;These directories stores script files that anacron needs to execute at different intervals. this is configured in /etc/anacrontab&lt;/td&gt;&lt;td class="column-4"&gt;if script logrotate is present in /etc/cron.daily/, it means the script is to be executed daily&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;!-- #tablepress-4 from cache --&gt;&lt;/p&gt;&#10;&lt;h4 class="wp-block-heading"&gt;An anacron example: logrotate&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Rotating logs is a common task in Linux that can be done by logrotate. To understand how this works, first, make sure cronie-anacron package is installed and crond.service is up. Then examine the /etc/anacrontab file:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# /etc/anacrontab: configuration file for anacron&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# See anacron(8) and anacrontab(5) for details.&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;SHELL&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/bin/sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;PATH&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/sbin:/bin:/usr/sbin:/usr/bin&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;MAILTO&lt;span style="color:#f92672"&gt;=&lt;/span&gt;root&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# the maximal random delay added to the base delay of the jobs&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;RANDOM_DELAY&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;45&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;# the jobs will be started during the following hours only&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;START_HOURS_RANGE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;3-22&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#period in days delay in minutes job-identifier command&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt; cron.daily nice run-parts /etc/cron.daily&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;7&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;25&lt;/span&gt; cron.weekly nice run-parts /etc/cron.weekly&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;@monthly &lt;span style="color:#ae81ff"&gt;45&lt;/span&gt; cron.monthly nice run-parts /etc/cron.monthly&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This indicates that daily, weekly and monthly jobs are active. Go into /etc/cron.daily/, and examine script logrotate:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;#!/bin/sh&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;/usr/sbin/logrotate -s /var/lib/logrotate/logrotate.status /etc/logrotate.conf&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;EXITVALUE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$?&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;if&lt;/span&gt; &lt;span style="color:#f92672"&gt;[&lt;/span&gt; $EXITVALUE !&lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#f92672"&gt;]&lt;/span&gt;; &lt;span style="color:#66d9ef"&gt;then&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; /usr/bin/logger -t logrotate &lt;span style="color:#e6db74"&gt;&amp;#34;ALERT exited abnormally with [&lt;/span&gt;$EXITVALUE&lt;span style="color:#e6db74"&gt;]&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;fi&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;exit &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;This indicates that logrotate loads configuration from /etc/logrotate.conf, the man page of logrotate explains how this configuration works, along with an example. If you have any custom application where the log file needs rotated, it can be configured in this file.&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/2018/04/basics-of-linux-os/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Basics Terms in Linux OS&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2018/06/text-processing-with-linux-bash/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Linux Admin Basics 3 of 3 – text processing, regex, sed &amp;amp; awk&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>Basics Terms in Linux OS</title><link>https://static.digihunch.com/2018/04/basics-of-linux-os/</link><pubDate>Tue, 24 Apr 2018 19:16:00 -0400</pubDate><guid>https://static.digihunch.com/2018/04/basics-of-linux-os/</guid><description>&lt;p class="wp-block-paragraph"&gt;These are the things quite confusing or abstract while I was at school but now makes lots of sense after many years working with different flavours of OS.&lt;/p&gt;&#10;&lt;h4 class="wp-block-heading"&gt;&lt;strong&gt;GPL and BSD as software license types&lt;/strong&gt;&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The main difference is that BSD (Berkeley Software Distribution) is a permissive (non-protective) license, while GPL(GNU General Public License) is a copyleft (protective) license.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Permissive licenses do not protect the code from being used in non-open source apps and apply no restrictions on the derivatives, while copyleft licenses force the creator of derivatives or re-distributor of the software to open the modified code. Under GPL you can&amp;#8217;t sub-license, meaning, you can’t change any of the original license terms or introduce any of your own. You’re also required to state all the changes you make to the original code. That is why components licensed under GPL and other copyleft licenses should be avoided in commercial products that would later be distributed under proprietary licenses.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;The BSD license family (including the Modified BSD License), on the other hand, doesn’t compel you to do any of the above. They have fairly relaxed redistribution terms.&lt;/p&gt;&#10;&lt;h4 class="wp-block-heading"&gt;&lt;strong&gt;GNU/Linux and BSD as operating systems&lt;/strong&gt;&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Unix &lt;/strong&gt;&amp;#8211; the name of the original system designed at AT&amp;amp;T in the 1970s. At the time, it featured a great deal of novelties such as multi-tasking, multi-user support, time sharing, etc. It was made portable by using C language.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Linux Kernel&lt;/strong&gt; &amp;#8211; a free, open-source, monolithic, Unix-like OS kernel. It was conceived and created in 1991 by Linus Torvalds for his personal computer. The word Linux, technically, is just the kernel. By itself, Linux (Kernel) has no place for user to land (e.g. no apps, no commands)&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;GNU/Linux&lt;/strong&gt; &amp;#8211; GNU project has developed a comprehensive set of free software tools for use with Unix and Linux. GNU/Linux involves the software tools along with the Linux Kernel.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;GNU/Linux distribution&lt;/strong&gt; &amp;#8211; ready-to-use full OS, including Linux Kernel, GNU library and tools, whose developers have made a commitment to follow GNU GFSD, X Window and desktop environment (e.g. KDE, GNOME) and includes many pieces of software. GNU/Linux distro is what many people refer to as &amp;#8220;Linux&amp;#8221;, and it includes Debian, Ubuntu, RedHat and CentOS. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;BSD (Berkeley Software Distribution) &amp;#8211; an OS based on Research Unix, originally developed at Bell Labs, eventually grown into a complete operating system. Today, &amp;#8220;BSD&amp;#8221; often refers to its decendants, such as FreeBSD, OpenBSD, NetBSD, or DragonFly BSD. Each of these are both a kernel and an operating system. Another famous BSD descendant is Darwin, which is what Mac OS X based on.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Comparing &amp;#8220;BSD&amp;#8221; with &amp;#8220;Linux&amp;#8221;&lt;/strong&gt; &amp;#8211; Linux is more popular and tends to support new hardware sooner. Typical users usually don&amp;#8217;t feel the difference between them. FreeBSD as desktop OS uses the same GNOME, KDE, or Xfce desktop environments that many flavours of Linux use as well. Although you need to install the desktop environment yourself. Another important difference is the licensing model as mentioned above between GPL and BSD. This article is a good reference about all the differences bewteen &amp;#8220;BSD&amp;#8221; and &amp;#8220;Linux&amp;#8221;&lt;br&gt; https://www.educba.com/linux-vs-bsd/&lt;/p&gt;&#10;&lt;h4 class="wp-block-heading"&gt;&lt;strong&gt;Swap, Cache and Buffer&lt;/strong&gt;&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Swap &lt;/strong&gt;&amp;#8211; swap file or swap partition. The primary function is to substitute disk space for RAM memory when real RAM fills up and more space is needed. The kernel uses a memory management program that detects blocks, aka pages, of memory in which the contents have not been used recently. The memory management program swaps enough of these relatively infrequently used pages of memory out to a special partition on the hard drive specifically designated for “paging”, or swapping. This frees up RAM and makes room for more data to be entered into your spreadsheet. Those pages of memory swapped out to the hard drive are tracked by the kernel’s memory management code and can be paged back into RAM if they are needed.&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;&lt;strong&gt;Swapping &lt;/strong&gt;moves entire process between main memory and secondary storage; this is the original Unix method and can cause severe performance loss;&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Paging &lt;/strong&gt;moves small unites of memory (i.e. pages with 4Kbytes). It is more efficient and was added to BSD&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In both cases, least recently used memory is moved to secondary storage and back to main memory only when needed again. In Linux, the term swapping is used to refer to paging. Older Unix-style swapping of entire thread and process is no longer supported.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;CPU Cache&lt;/strong&gt; &amp;#8211; a hardware cache used by CPU to reduce the average time to access data from the main memory. A cache is a smaller, faster memory, located closer to a processor core, which stores copies of the data from frequently used main memory locations. Most CPUs have different independent caches, inclusing insructions and data caches, where the data cache is usually organized as a hierarchy of more cache levels (L1, L2, L3, L4, etc)&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Page Cache (or disk cache)&lt;/strong&gt; &amp;#8211; kept by the OS in computer&amp;#8217;s main memory and controlled by the computer. The OS keeps a page cached in otherwise unused portions of the main memory, resulting in quicker access to the contents of cached pages and overall performance.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Disk Buffer&lt;/strong&gt; &amp;#8211; (or ambiguously called disk cache or cache buffer) the embedded memory in a hard disk drive acting as a buffer between the rest of the computer and the physical hard disk platter that is used for storage. Modern hard disk drives come with 8 to 256 MiB of such memory. Disk buffer is physically distinct from and is used differently from page cache. It is controlled by the microcontroller in the hard disk drive.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;GRUB (GNU GRand Unified Bootloader)&lt;/strong&gt; &amp;#8211; a boot loader package from GNU project. It is predominantly used for Unix-like systems. Current version is GRUB2&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;System call&lt;/strong&gt; &amp;#8211; In computing, a system call is the programmatic way in which a computer program requests a service from the kernel of the operating system it is executed on. This may include hardware-related services (for example, accessing a hard disk drive), creation and execution of new processes, and communication with integral kernel services such as process scheduling. System calls provide an essential interface between a process and the operating system. Below is a list of key system calls:&lt;/p&gt;&#10;&lt;figure class="wp-block-table is-style-stripes"&gt;&lt;table class="has-background" style="background-color:#e9fbe5"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;System Call&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;read()&lt;/td&gt;&lt;td&gt;read bytes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;write()&lt;/td&gt;&lt;td&gt;write bytes&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;open()&lt;/td&gt;&lt;td&gt;open a file&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;close()&lt;/td&gt;&lt;td&gt;close a file&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;fork()&lt;/td&gt;&lt;td&gt;create a new process&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;exec()&lt;/td&gt;&lt;td&gt;execute a new program&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;connect()&lt;/td&gt;&lt;td&gt;connect to a network host&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;accept()&lt;/td&gt;&lt;td&gt;accept a network connection&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;stat()&lt;/td&gt;&lt;td&gt;fetch file statistics&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ioctl()&lt;/td&gt;&lt;td&gt;set I/O properties, or other miscellaneous functions&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;mmap()&lt;/td&gt;&lt;td&gt;map a file to the memory address space&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;brk()&lt;/td&gt;&lt;td&gt;extend the heap pointer&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/figure&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;&lt;a href="http://man7.org/linux/man-pages/man2/syscalls.2.html"&gt;strace &lt;/a&gt;&lt;/strong&gt;is the tool to trace system calls and signals in Linux. &lt;/p&gt;&#10;&lt;h4 class="wp-block-heading"&gt;&lt;strong&gt;sysVinit, runit and systemd&lt;/strong&gt;&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;init &lt;/strong&gt;&amp;#8211; in Unix-based OS, init is the first process started during booting of OS. Init is a daemon process that continues running until the system is shutdown. It is the direct or indirect ancestor of all other processes and automatically adopts all orphaned processes. Init is started by the kernel during the booting process; a kernel panic will occur if the kernel is unable to start it. Init is typically assigned process identifier 1 and its job is to start other programs that are essential to the operation of your system. All other processes are descended from init.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;init systems&lt;/strong&gt;&lt;br&gt; Linux has several options as init systems. For example: sysvinit, runit, systemd and upstart. Here is a comparison of commands involved in managing each. &lt;br&gt; http://unix.cafe/wp/en/2017/07/howto-manage-a-service-in-systemd-sysvinit-upstart-runit-and-openrc/&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;SysV init&lt;/strong&gt; &amp;#8211; System initialization process is handled by the init daemon. One of the original daemon is SysVinit, which is a collection of System V-style init programs. init process starts serially. It is a run-once process during the start of the OS. One task starts only after the last task startup was successful and it was loaded in the memory. This often resulted in delayed and long booting time. &lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Runit &lt;/strong&gt;&amp;#8211; an init scheme for Unix-like operating systems that initializes, supervises, and ends processes throughout the operating system. It is a replacement of sysvinit and features brevity and simplicity.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Systemd &lt;/strong&gt;&amp;#8211; A init replacement daemon designed to start process in parallel, implemented in a number of standard distribution – Fedora, OpenSuSE, Arch, RHEL, CentOS, etc. Its flexibility comes with more complexity. It is an event driven init system, that not only starts stuff at boot (hence managing dependencies), but also after that. It also keeps track of many things after boot, such as mounts, availability of services, integration with resource management, etc. Because of that, systemd is also good at logging and monitoring. Systemd allows services to start when:&lt;/p&gt;&#10;&lt;ul class="wp-block-list"&gt;&lt;li&gt;the system boots&lt;/li&gt;&lt;li&gt;a hardware components attaches to the system&lt;/li&gt;&lt;li&gt;other service started&lt;/li&gt;&lt;li&gt;a timer fires&lt;/li&gt;&lt;/ul&gt;&#10;&lt;p class="wp-block-paragraph"&gt;To determine which system initialization method your current Linux distribution is using (SysVinit or systemd), simply check process id 1:&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt; $ ps -p 1&lt;/p&gt;&#10;&lt;h4 class="wp-block-heading"&gt;&lt;strong&gt;Soft link and hard link&lt;/strong&gt;&lt;/h4&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;inode &lt;/strong&gt;&amp;#8211; stores the attributes and disk block locations of a file or directory&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Soft/Symbolic link&lt;/strong&gt; &amp;#8211; essentially a shortcut to another file. The link itself is a separate file, pointing to the destination file or directory. The inode of the file is different from that of the symbolic link. Deleting the destination file will leave the symbolic link file a &amp;#8220;dangling link&amp;#8221;. Symbolic file may also have different permissions from the destination file or directory.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;&lt;strong&gt;Hard link&lt;/strong&gt; &amp;#8211; essentially an alias of a file. The link itself is not a separate file, and the destination can only be a file (no directory). The inode of the link the the same as the file itself. So there is actually no distinction between destination file and link. Both files are equal. If you delete the file, the link continue to work until the number of hard links to the file becomes zero.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Soft link points to a file by name whereas hard link points by inode number.&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/2018/04/centos-remove-swap-safely/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;CentOS – Remove Swap safely&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2018/05/cron-and-logrotate-in-centos/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;cron and anacron in RedHat Linux (How logrotate works)&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item><item><title>CentOS – Remove Swap safely</title><link>https://static.digihunch.com/2018/04/centos-remove-swap-safely/</link><pubDate>Sat, 14 Apr 2018 16:15:43 -0400</pubDate><guid>https://static.digihunch.com/2018/04/centos-remove-swap-safely/</guid><description>&lt;p class="wp-block-paragraph"&gt;If the default installation has swap on, you will see it from block device list:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@server /&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# lsblk&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sda 8:0 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 500G &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; disk&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;├─sda1 8:1 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 1G &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; part /boot&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;└─sda2 8:2 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 499G &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; part&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ├─centos-root 253:0 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 50G &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; lvm /&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ├─centos-swap 253:1 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 7.9G &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; lvm &lt;span style="color:#f92672"&gt;[&lt;/span&gt;SWAP&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; └─centos-home 253:2 &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; 441.1G &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; lvm /home&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;sr0 11:0 &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; 1024M &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; rom&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@server /&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# free -h&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; total used free shared buff/cache available&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Mem: 7.6G 217M 7.2G 11M 206M 7.2G&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Swap: 7.9G 0B 7.9G&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Many installations require swap to be off for performance reasons (although some advocate turning off &lt;a href="https://www.howtogeek.com/449691/what-is-swapiness-on-linux-and-how-to-change-it/"&gt;swappiness&lt;/a&gt; of the application, instead of removing swap partition from operating system, which is a separate topic). This can be turned off by a simple 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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;swapoff -a&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Then if you run free command after rebooting, you will see the Swap is set to 0G. Great. But lsblk and df commands still shows the space being used by swap. This disk space is not being used at all.&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@c7v-vitvcast02 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# free -m&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; total used free shared buff/cache available&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Mem: &lt;span style="color:#ae81ff"&gt;7802&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;237&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7380&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;11&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;185&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;7333&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Swap: &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;[&lt;/span&gt;root@c7v-vitvcast02 ~&lt;span style="color:#f92672"&gt;]&lt;/span&gt;&lt;span style="color:#75715e"&gt;# lvdisplay&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --- Logical volume ---&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Path /dev/centos/swap&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Name swap&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; VG Name centos&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV UUID 7zHtvT-zGYn-sNBc-JRlT-nTfU-O9hN-r07y3J&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Write Access read/write&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Creation host, time localhost, 2018-04-07 10:03:21 -0500&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Status available&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# open 0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Size &amp;lt;7.88 GiB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Current LE &lt;span style="color:#ae81ff"&gt;2016&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Segments &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Allocation inherit&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Read ahead sectors auto&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - currently set to &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Block device 253:1&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --- Logical volume ---&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Path /dev/centos/home&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Name home&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; VG Name centos&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV UUID 4XMTa7-uR44-qH0u-Oag4-PDyK-Z1BC-3oUSiz&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Write Access read/write&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Creation host, time localhost, 2018-04-07 10:03:22 -0500&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Status available&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# open 0&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Size &amp;lt;441.12 GiB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Current LE &lt;span style="color:#ae81ff"&gt;112926&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Segments &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Allocation inherit&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Read ahead sectors auto&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - currently set to &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Block device 253:2&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; --- Logical volume ---&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Path /dev/centos/root&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Name root&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; VG Name centos&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV UUID tkMCM4-cWxV-FaAC-hgJx-r1vS-DiY5-fyZvjt&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Write Access read/write&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Creation host, time localhost, 2018-04-07 10:03:22 -0500&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Status available&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;# open 1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; LV Size 50.00 GiB&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Current LE &lt;span style="color:#ae81ff"&gt;12800&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Segments &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Allocation inherit&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Read ahead sectors auto&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; - currently set to &lt;span style="color:#ae81ff"&gt;8192&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Block device 253:0&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;We can then remove the line for swap from /etc/fstab, this will keep the OS from mounting it upon reboot. However, the logical volume for swap is there, as a partition that&amp;#8217;s not exposed.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;If you need to reclaim space from swap partition, delete the logical volume:&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-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;lvremove /dev/centos/swap&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Do you really want to remove active logical volume centos/swap? &lt;span style="color:#f92672"&gt;[&lt;/span&gt;y/n&lt;span style="color:#f92672"&gt;]&lt;/span&gt;: y&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; Logical volume &lt;span style="color:#e6db74"&gt;&amp;#34;swap&amp;#34;&lt;/span&gt; successfully removed&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p class="wp-block-paragraph"&gt;Now, using command &lt;em&gt;lvdisplay&lt;/em&gt; or &lt;em&gt;lvs&lt;/em&gt;, the swap space is not displayed anymore. So I rebooted the server in the hopes that the swap space is not being presented and everything is hunky-dory. But no&amp;#8230; the server doesn&amp;#8217;t boot up at all. It took a long time at the splash screen only to enter dracut, where /boot isn&amp;#8217;t present.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;On further reading, this is because the grub file is still referencing /dev/centos/swap somewhere. I need to somehow get to the grub file and fix that before it can reboot again. Specifically, I pressed &amp;#8220;e&amp;#8221; at the menu, which gave me an opportunity to edit grub file. From there I removed section for swap. Then I saved it with &amp;#8220;Ctrl + X&amp;#8221; (as suggested on the screen) so the OS booted into normal mode. Alternatively, I entered &lt;a href="https://www.tecmint.com/boot-into-single-user-mode-in-centos-7/"&gt;single user mode&lt;/a&gt; in order to get to the point I can edit the grub file.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Once booted, I have to make change to the actual grub file at /boot/grub2/grub.cfg so the change persists. In the file, locate the lines starting with linux16 and remove the section &amp;#8220;rd.lvm.lv=centos/swap&amp;#8221;. There are two appearances of this section on my machine. Then the server will boot just normally.&lt;/p&gt;&#10;&lt;p class="wp-block-paragraph"&gt;In summary, the clean way to turn off swap on CentOS involves the following steps:&lt;/p&gt;&#10;&lt;ol class="wp-block-list"&gt;&lt;li&gt;turn off swap&lt;/li&gt;&lt;li&gt;Remove swap mount from /etc/fstab (and umount)&lt;/li&gt;&lt;li&gt;remove the logical volume for swap&lt;/li&gt;&lt;li&gt;remove reference to swap from grub&lt;/li&gt;&lt;/ol&gt;&#10;&lt;p class="wp-block-paragraph"&gt;Out of those steps, 3 and 4 are needed to reclaim swap spaces. They must be done together. If you rebooted the server before step 4. The server will not be able to boot complaining about missing swap.&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/2018/03/cassandra-architecture-summary/"&gt;&lt;span class="wp-post-navigation-label"&gt;Previous Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Cassandra Architecture&lt;/strong&gt;&lt;/a&gt;&#10;&lt;a rel="next" href="https://static.digihunch.com/2018/04/basics-of-linux-os/"&gt;&lt;span class="wp-post-navigation-label"&gt;Next Post&lt;/span&gt;&lt;strong class="wp-post-navigation-title"&gt;Basics Terms in Linux OS&lt;/strong&gt;&lt;/a&gt;&#10;&lt;/nav&gt;&#10;</description></item></channel></rss>