<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Roland 🐺</title>
    <description>The latest articles on DEV Community by Roland 🐺 (@skofgar).</description>
    <link>https://dev.to/skofgar</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F21613%2Fa376988b-0277-4561-bbd7-3c6f81f35d3b.jpg</url>
      <title>DEV Community: Roland 🐺</title>
      <link>https://dev.to/skofgar</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/skofgar"/>
    <language>en</language>
    <item>
      <title>Deploying a VM using AWS Cloud Formation</title>
      <dc:creator>Roland 🐺</dc:creator>
      <pubDate>Thu, 05 Nov 2020 04:34:08 +0000</pubDate>
      <link>https://dev.to/skofgar/deploying-a-vm-using-aws-cloud-formation-1im6</link>
      <guid>https://dev.to/skofgar/deploying-a-vm-using-aws-cloud-formation-1im6</guid>
      <description>&lt;h3&gt;
  
  
  Getting started with AWS CloudFormation by deploying a VM
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XMNrfuFC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A8xBNnG-9GZlyCuUK.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XMNrfuFC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A8xBNnG-9GZlyCuUK.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently I started using Amazon AWS and quickly realized that provisioning virtual machines, security policies and other network configurations is done one by one, which is tedious and needs to be automated. I had two options: either create a custom script to provision every single service or learn how to use CloudFormation.&lt;/p&gt;

&lt;p&gt;CloudFormation is a provisioning tool for AWS resources that requires a YAML/JSON formatted file inside which cloud infrastructure is described. This definitely seems like the better option, but being completely new to AWS the learning curve is steep and it is difficult to understand the terminology, the various components and how to combine them. Even the graphical user interface, the “CloudFormation Designer” is not that easy to use for new users.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mp0JR_n9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AbIj9ZTq_nwyku5oS.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mp0JR_n9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AbIj9ZTq_nwyku5oS.png" alt="Screenshot of the CloudFormation visual designer software. It allows to drag and drop components or modify JSON/YAML format."&gt;&lt;/a&gt;Screenshot of CloudFormation Designer&lt;/p&gt;

&lt;p&gt;What did I do? First I learned how to provision all the components manually one by one, which took more time than I would like to admit, but was essential for me to understand the components and which ones depend on another. Eventually manually provisioning resources became easier and all the different services became familiar, that allowed me to transition my set up to CloudFormation. It was a long process. Hopefully this article will allow others to use CloudFormation much sooner.&lt;/p&gt;

&lt;p&gt;It’s difficult to cover all scenarios and edge cases, so please be prepared to dig through some AWS documentation and learn more about some of the individual components. Unfortunately, there are always some road bumps…&lt;/p&gt;

&lt;p&gt;However, I’m confident, that providing you with my configuration example will make learning CloudFormation easier. There are a few things I will skim over for the sake of keeping this article short and to the point. Please use the comment section to provide feedback and ask questions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Goal
&lt;/h4&gt;

&lt;p&gt;The goal of this tutorial is to set up a single virtual machine and expose it to the internet using CloudFormation.&lt;/p&gt;

&lt;h4&gt;
  
  
  Requirements
&lt;/h4&gt;

&lt;p&gt;To follow this tutorial an AWS account is required. The AWS command line interface is not needed.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;AWS has a free tier, that should allow you to follow this tutorial at no cost: &lt;a href="https://aws.amazon.com/free/"&gt;https://aws.amazon.com/free/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  AWS services and resources
&lt;/h4&gt;

&lt;p&gt;The following AWS services, also referred to as resources, are needed for a simple virtual machine (VM) setup:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Stack&lt;/strong&gt;  — A set of resources provisioned and managed by CloudFormation is referred to as a  &lt;strong&gt;&lt;em&gt;Stack&lt;/em&gt;&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image&lt;/strong&gt;  — Images (&lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html"&gt;AMI&lt;/a&gt;) describe the root volume of a virtual machine. &lt;em&gt;For example they can contain the operating system or application server.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Virtual Machine —&lt;/strong&gt;  It’s basically an artificial computer. It behaves like an actual computer but does not physically exist. It exists and runs on a server. Virtual Machines come in different sizes (CPU, Memory (RAM) and other hardware components) and can be based on different images.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Storage Volume&lt;/strong&gt;  — A hard drive that is plugged into the virtual machine.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security Group&lt;/strong&gt;  — &lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html"&gt;Security group&lt;/a&gt; is a &lt;em&gt;virtual firewall&lt;/em&gt; for our set up in AWS. It controls all traffic in and out of segment (VPC) of the AWS cloud.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;VPC&lt;/strong&gt;  — Every computer and cloud infrastructure needs networking. To protect our &lt;em&gt;instance&lt;/em&gt; in AWS, we create a &lt;em&gt;virtual&lt;/em&gt; network, exclusive for our purpose, also called a &lt;a href="https://docs.aws.amazon.com/vpc/latest/userguide/what-is-amazon-vpc.html"&gt;&lt;em&gt;Virtual Private Cloud&lt;/em&gt;&lt;/a&gt; (VPC)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subnet &lt;/strong&gt; — &lt;strong&gt; &lt;/strong&gt; A subnet defines the range of IP addresses in our VPC&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Route Table&lt;/strong&gt;  — Defines and determines traffic flow&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Internet Gateway&lt;/strong&gt;  — Internet Gateways enable communication between our VPC and the internet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Elastic IP Address&lt;/strong&gt;  — An Elastic IP Address is a static IPv4 address. It can be reused and point to different VPCs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CIDR blocks&lt;/strong&gt;  — &lt;a href="https://en.wikipedia.org/wiki/Classless_Inter-Domain_Routing"&gt;CIDR blocks&lt;/a&gt; define valid IP address ranges and are needed by Subnets&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Associations&lt;/strong&gt;  — CloudFormation requires associating certain components with each other. &lt;em&gt;For example a Subnet and a Routing Table&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;KeyPair&lt;/strong&gt;  — Amazon EC2 requires keys for accessing a virtual machine. These ssh keys are referred to as KeyPairs and often the KeyName (name of the key) is required for the creation of virtual machines. Table 1: Overview of AWS Components needed for a CloudFormation set up&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  The CloudFormation definition file
&lt;/h4&gt;

&lt;p&gt;The CloudFormation file defines what we want to provision. It can define all the components above and &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-reference.html"&gt;much more&lt;/a&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I think of it as &lt;em&gt;the one file to rule them all&lt;/em&gt;, even though you can have as many CloudFormation definition files as you want.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The definition file can be written in either &lt;a href="https://www.json.org/json-en.html"&gt;JSON&lt;/a&gt; or &lt;a href="https://yaml.org"&gt;YAML&lt;/a&gt;. I chose YAML because the notation is shorter and it’s easy to add comments. Feel free to use the notation of your choice though, the CloudFormation designer can convert between either format with a simple click.&lt;/p&gt;

&lt;p&gt;The basic structure my template uses entails 3 major sections (&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html#template-anatomy-sections"&gt;there are more&lt;/a&gt;, but we don’t need them right now).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Parameters&lt;/li&gt;
&lt;li&gt;Mappings&lt;/li&gt;
&lt;li&gt;Resources&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Parameters
&lt;/h4&gt;

&lt;p&gt;The Parameters section allows for the definition of inputs that can be provided through the AWS interface or the AWS CLI when creating an instance. It’s optional, but quite useful to make our configurations more reusable. In this section we define parameter-name, expected value type, data value validation, description and default value. They’re especially useful once we get really comfortable with CloudFormation.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Parameters:
  KeyName:
    Default: 'EC2Key'
    Description: 'Enter name of an existing EC2 KeyPair to enable SSH access to the instance'
    Type: 'AWS::EC2::KeyPair::KeyName'
    ConstraintDescription: Name of an existing EC2 KeyPair.
  StackPostfix:
    Default: 'vm-1'
    Description: 'Postfix for this vm stack. This is purely for ease of use, to recognize a particular VM more easily.'
    Type: String
    MinLength: '1'
    MaxLength: '64'
  InstanceType:
    Description: 'WebServer EC2 instance type. Change based on application needs.'
    Type: String
    Default: t2.micro
    AllowedValues:
      - t1.micro
      - t2.nano
      - t2.micro
      - t2.small
      - t2.medium
      - t2.large
    ConstraintDescription: must be a valid EC2 instance type.
  CidrBlock:
    Description: 'Enter CIDR block that the VPC should use. Example: 10.0.0.0/16'
    Type: String
    MinLength: '9'
    MaxLength: '18'
    Default: 10.0.0.0/16
    AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})'
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
  LimitedSSHAccess:
    Description: 'Enter CIDR for network that may access via SSH'
    Type: String
    MinLength: '9'
    MaxLength: '18'
    Default: 0.0.0.0/0
    AllowedPattern: '(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})/(\d{1,2})'
    ConstraintDescription: must be a valid IP CIDR range of the form x.x.x.x/x.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my template I’m defining 5 parameters with following default values:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The &lt;strong&gt;EC2 key&lt;/strong&gt; that may be used to connect to the EC2 instance. A key is required to connect to your VM via SSH. When creating an EC2 instance manually through the web interface AWS will offers to create one for you. However, when using CloudFormation we need to create a key beforehand.&lt;/li&gt;
&lt;li&gt;The StackPostfix, is of no functional value, it just describes a string that will be appended to all the components that this CloudFormation template will create. I find it helpful to have a consistent postfix throughout all resources when looking at them through the AWS console. It allows for quick identification, which virtual machines all resources belong to. The default value is vm-1.&lt;/li&gt;
&lt;li&gt;The instance type defines which EC2 &lt;a href="https://aws.amazon.com/ec2/instance-types/"&gt;virtual machine instance type&lt;/a&gt; should be provisioned. For testing purposes it is configured to use one of the smallest available instances types: t2.micro.&lt;/li&gt;
&lt;li&gt;The “CIDR block” describes what IP range the VPC should be using internally.&lt;/li&gt;
&lt;li&gt;The “LimitedSSHAccess” parameter allows you to restrict which IP addresses may access the virtual machine via SSH. It’s a good idea to restrict this to the smallest possible IP range. E.g. your personal IP address. If you don’t know which IP address range to use, set it to 0.0.0.0/0, this will allow SSH access from anywhere.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;Documentation:&lt;/em&gt; &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/parameters-section-structure.html"&gt;&lt;em&gt;AWS Parameters&lt;/em&gt;&lt;/a&gt;, &lt;a href="https://aws.amazon.com/ec2/instance-types/"&gt;&lt;em&gt;AWS Instance Types&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Mappings
&lt;/h4&gt;

&lt;p&gt;At its core, mappings are just plain key-value matching. We mainly use them in our configuration to map to EC2 instance types — which kind of machines we want to provision (size-wise) and what images we want to use on said instances. AWS provides a large variety of existing images ranging from Windows to Linux distributions or even allowing us to uploading our own. For this tutorial we’ll use an existing Linux based &lt;em&gt;Amazon Machine Image (AMI)&lt;/em&gt;, that is already provided and that already comes with pre-installed software.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--F7jHi5Fq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ADS7Xef2wMZgOIqGk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--F7jHi5Fq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ADS7Xef2wMZgOIqGk.png" alt=""&gt;&lt;/a&gt;An example of Amazon’s image marketplace. This screenshot is taken from the AWS Console, during an EC2 instance creation process.&lt;/p&gt;

&lt;p&gt;While all images types can be viewed through the general catalog under &lt;a href="https://aws.amazon.com/marketplace"&gt;https://aws.amazon.com/marketplace&lt;/a&gt;, we do need to access the EC2 instance creation page at least once, to retrieve the &lt;em&gt;Image ID’s&lt;/em&gt; that allow Cloud Formation to understand which exact image we need for our virtual machine that we are going to create. These Image ID’s &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/walkthrough-custom-resources-lambda-lookup-amiids.html"&gt;are region and instance specific&lt;/a&gt;. A Linux image in us-west-1 does not have the same ID in us-west-2. Therefore we need to create all the mappings, based on regions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;AWSRegionArch2AMI:
    # Note that image's are AWS region specific. Hence,
    # the "same" image has to be defined per region
    # and the image ID's will vary and additional mappings
    # may need to be added
    us-west-1: #
      # AWS image, comes with docker pre-installed
      HVMA2018: ami-09a3e40793c7092f5 
      # Ubuntu 18
      HVMU18: ami-0d705db840ec5f0c5
    us-east-1: #
      HVMA2018: ami-032930428bf1abbff
      HVMU18: ami-0ac80df6eff0e70b5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;The marketplace is quite useful, it also gives you estimates on how expensive machines are in certain regions. For example review the pricing information section &lt;a href="https://aws.amazon.com/marketplace/pp/B08BG6S76F?qid=1603601783392&amp;amp;sr=0-1&amp;amp;ref_=srh_res_product_title"&gt;of this image&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Feel free to browse the &lt;a href="https://aws.amazon.com/marketplace/ref=csl_ec2_ami"&gt;AMI Marketplace&lt;/a&gt; for &lt;em&gt;Elastic Compute Cloud (EC2)&lt;/em&gt; yourself and discover what other images they have to offer.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Documentation:&lt;/em&gt; &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/mappings-section-structure.html"&gt;&lt;em&gt;AWS Mappings&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AMIs.html#ami-using"&gt;&lt;em&gt;Amazon Machine Images (AMI)&lt;/em&gt;&lt;/a&gt;&lt;em&gt;,&lt;/em&gt; &lt;a href="https://aws.amazon.com/marketplace/ref=csl_ec2_ami"&gt;&lt;em&gt;AMI Marketplace&lt;/em&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Resources
&lt;/h4&gt;

&lt;p&gt;Resources are the bits and pieces we need from Amazon. It’s all the components we described earlier.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that in the following example, I defined resources with the names VM, FormationSecurityGroup, VMvpc, VMInternetGateway,...&lt;br&gt;&lt;br&gt;
These names can be customized. The information that tells CloudFormation what the desired resources are is captured in the Type field.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Resources:
  # Define an EC2 instance. This is our virtual machine
  VM:
    Type: 'AWS::EC2::Instance'
    ...

  # This defines the Security Group, used for the VM above
  FormationSecurityGroup:
    Type: 'AWS::EC2::SecurityGroup'
    ...

  # This defines the VPC
  VMvpc:
    Type: AWS::EC2::VPC
    ...

  # This defines the Internet Gateway
  VMInternetGateway:
    Type: AWS::EC2::InternetGateway
    ...

  # This attaches the Internet Gateway (IGW) to a VPC
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    ...

  # This defines a Subnet
  VMSubnet:
    Type: AWS::EC2::Subnet
    ...

  # This defines the Routing Tables for our subnets
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    ...

  # This defines the routes. Public route table 
  # has direct routing to IGW
  PublicRouteVM:
    Type: AWS::EC2::Route
    ...

  # Associate Routing Table to Subnet
  SubnetRouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    ...

  # This defines the Elastic IP Address. 
  # On creation AWS will provision an
  # IP address and will then be usable for your VM
  ElasticIPAddress:
    Type: AWS::EC2::EIP
    ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is just a basic structure of what goes into the resource section of the configuration file. Review &lt;a href="https://gitlab.com/-/snippets/2033103"&gt;the entire template&lt;/a&gt; for more details.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Documentation:&lt;/em&gt; &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-template-resource-type-ref.html"&gt;&lt;em&gt;Resources Reference&lt;/em&gt;&lt;/a&gt;, &lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html#template-anatomy-sections"&gt;Template Structure / Anatomy&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Provision a virtual machine
&lt;/h4&gt;

&lt;p&gt;Now that the most important components and pieces are covered, we can provision the virtual machine. The following 4 steps walk us through the creation of a set of SSH keys for AWS, how to submit the template to the CloudFormation designer and how to create a &lt;em&gt;Stack&lt;/em&gt; with it. Lastly we will run a small web server to validate a successful deployment and cleanup the stack.&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Create KeyPair
&lt;/h4&gt;

&lt;p&gt;Go to the EC2 management and create a KeyPair. If you’re using North California (us-west-1) you may use &lt;a href="https://us-west-1.console.aws.amazon.com/ec2/v2/home?region=us-west-1#KeyPairs:"&gt;this link&lt;/a&gt; and select "create key pair". For a different region, make sure to change to select the desired location in the top right menu, then go to the "EC2" service &amp;gt; scroll down to "Network &amp;amp; Security" &amp;gt; "Key Pairs".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EJ5Nhw35--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AQnAlaptpUNLbmWaC.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EJ5Nhw35--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AQnAlaptpUNLbmWaC.png" alt=""&gt;&lt;/a&gt;Example for a new KeyPair with name &lt;em&gt;VMKey-NorthCalifornia&lt;/em&gt; and the file format pem.&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Open the CloudFormation designer
&lt;/h4&gt;

&lt;p&gt;The CloudFormation designer can be opened from the website &lt;a href="https://aws.amazon.com/cloudformation/"&gt;https://aws.amazon.com/cloudformation/&lt;/a&gt; or from the AWS Console by navigating to the CloudFormation service and then selecting “Create Stack” and then “Create template in Designer”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--u1ZZU_Xu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AKPlgPySf-dWZHHbA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--u1ZZU_Xu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AKPlgPySf-dWZHHbA.gif" alt=""&gt;&lt;/a&gt;Opening CloudFormation designer (GIF animation)&lt;/p&gt;

&lt;p&gt;After opening the designer, select “template” at the bottom left and then change the editor template language from JSON to YAML.&lt;/p&gt;

&lt;p&gt;Then &lt;strong&gt;copy&lt;/strong&gt; &lt;a href="https://gitlab.com/skofgar/cloudformation/-/blob/master/formation.yaml"&gt;&lt;strong&gt;my template from GitLab&lt;/strong&gt;&lt;/a&gt; &lt;strong&gt;into the template viewer&lt;/strong&gt; and select refresh in the top right. The interface should then update and display something like the screenshot below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XE4y3iEI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ASUhY8KRAVTBdCV7U.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XE4y3iEI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2ASUhY8KRAVTBdCV7U.png" alt=""&gt;&lt;/a&gt;Screenshot of CloudFormation designer, after pasting my template.&lt;/p&gt;

&lt;p&gt;The YAML defines all the resources and associates individual components together. Feel free to browse through it and review all the components. I added comments that hopefully explain what most of the various resources do and what they are for.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make sure to update the LimitedSSHAccess CIDR block to an IP range that works for you, before proceeding, otherwise you won't be able to access the machine later.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Example, if your IP address is&lt;/em&gt; &lt;em&gt;67.188.42.123 a possible CIDR block would be&lt;/em&gt; &lt;em&gt;67.188.0.0/16&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When ready, submit the design to the CloudFormation service by selecting the “Create Stack” button in the top left.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BhLQjXJj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/626/0%2AUidP8tm0c7DZ33kb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BhLQjXJj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/626/0%2AUidP8tm0c7DZ33kb.png" alt=""&gt;&lt;/a&gt;Screenshot of the &lt;em&gt;Create Stack&lt;/em&gt; button.&lt;/p&gt;

&lt;p&gt;The CloudFormation stack creation process should be displayed and “template is ready” should be selected. When ready, select “Next”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3qatbzPO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AOcKGGyrl6y5fGCF4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3qatbzPO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AOcKGGyrl6y5fGCF4.png" alt=""&gt;&lt;/a&gt;Screenshot of the Create Stack screen, now using the template we created in the CloudFormation designer.&lt;/p&gt;

&lt;p&gt;The stack detail screen will be displayed next, asking for a name for the stack and allowing the parameters to be changed. Change them as desired and make sure to change the “KeyName” to the KeyPair that was previously created in the EC2 AWS service section.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--R4QiUk8A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AQ2fNM3A6O4OAKGt_.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--R4QiUk8A--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AQ2fNM3A6O4OAKGt_.png" alt=""&gt;&lt;/a&gt;Screenshot of the stack detail screen. This step requires a name for the CloudFormation stack to be added and allows parameters to be overridden. Make sure to update the KeyName to the KeyPair that has been created for your account for the selected AWS region.&lt;/p&gt;

&lt;p&gt;Once the details section is complete continue selecting next until we reach the “review” screen and select “Create stack” after verifying all values.&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Creating the CloudFormation stack
&lt;/h4&gt;

&lt;p&gt;CloudFormation will now provision the EC2 instance and all required components. The events section can be manually refreshed and will contain more event entries over time as CloudFormation provisions more and more of the requested resources.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--w88lPjds--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2Ao1h_ugqZhJyL9OEZ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--w88lPjds--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2Ao1h_ugqZhJyL9OEZ.png" alt=""&gt;&lt;/a&gt;Screenshot of CloudFormation stack creation page. It shows that a stack creation just started.&lt;/p&gt;

&lt;p&gt;Should an error occur, the entire stack creation will be aborted and any resources of the stack, that were successfully created, will be removed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Yob6my_9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2At3c7xAcyLU4IUS63.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Yob6my_9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2At3c7xAcyLU4IUS63.png" alt=""&gt;&lt;/a&gt;Screenshot of a potential error that may occur. In case of a problem CloudFormation will abort, automatically rollback and undo any created resources. Check the Events log for information on what happened. — The resolution for this particular problem was waiting a few hours for a verification email by Amazon and then simply attempting the stack creation again.&lt;/p&gt;

&lt;p&gt;If everything goes well CloudFormation will eventually switch from CREATE_IN_PROGRESS to CREATE_COMPLETE.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--olMsq_h4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AxEhZnqJgR1Cf_0Hd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--olMsq_h4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AxEhZnqJgR1Cf_0Hd.png" alt=""&gt;&lt;/a&gt;Screenshot of CloudFormation Stack creation screen after it successfully completed. Note how on the left a message “CREATE_COMPLETE” is being displayed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wYmPhxsG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/888/0%2ArBpMObjJMSn76yHi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wYmPhxsG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/888/0%2ArBpMObjJMSn76yHi.png" alt=""&gt;&lt;/a&gt;Screenshot of CloudFormation Stack “Resource” tab, listing all the provisioned resources and the corresponding status.&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Review running VM instance
&lt;/h4&gt;

&lt;p&gt;If everything works out as expected, the instance of our VM should be running and accessible via the internet. In &lt;a href="https://us-west-1.console.aws.amazon.com/cloudformation/home"&gt;the CloudFormation section of AWS&lt;/a&gt; the &lt;em&gt;CloudFormationDemo&lt;/em&gt; stack should be successfully created and listed.&lt;/p&gt;

&lt;p&gt;By opening the &lt;a href="https://us-west-1.console.aws.amazon.com/console"&gt;AWS Console website&lt;/a&gt; we can &lt;a href="https://us-west-1.console.aws.amazon.com/ec2/v2/home"&gt;navigate to EC2&lt;/a&gt; and should see a running instance of vm-1. Furthermore, under "Network &amp;amp; Security" &amp;gt; Elastic IP addresses, the public IP address with which we can reach our virtual machine can be reached, should be listed as well.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sRbURtwG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AO8-Hb1dhqBJwYbNx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sRbURtwG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AO8-Hb1dhqBJwYbNx.png" alt=""&gt;&lt;/a&gt;Screenshot of EC2 services overview&lt;/p&gt;

&lt;p&gt;Navigating to the VPC services should allow us to see the definitions of the VPC, subnets, routing tables and internet gateways.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Gj7AQ6NL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AEp8xnfxYZ6Qy0xYH.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Gj7AQ6NL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AEp8xnfxYZ6Qy0xYH.png" alt=""&gt;&lt;/a&gt;Screenshot of VPC services overview&lt;/p&gt;

&lt;p&gt;Currently there’s not much to see when hitting the public IP address of the virtual machine. However, by SSH’ing into the machine using ssh -i {KEY_PAIR_NAME}.pem ec2-user@{IP-ADDRESS} and then starting a Python web server, it should be possible to see the following page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#### Connect to VM
# Replace KeyPair and IP address placeholder
# The IP address is whitelisted through the 
# LimitedSSHAccess parameter
ssh -i {KEY_PAIR_NAME}.pem ec2-user@{IP-ADDRESS}

#### Create and use demo directory
mkdir ~/demo
cd demo

#### Create dummy website
echo "&amp;lt;h1&amp;gt;Hello World&amp;lt;/b&amp;gt;" &amp;gt; ~/demo/index.html

#### Start web server 
# The use of port 80 is defined in the
# FormationSecurityGroup 
sudo python -m SimpleHTTPServer 80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Generally we should avoid using sudo.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--U7XvX6M9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A1IAX-k4er3aIZv_A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--U7XvX6M9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A1IAX-k4er3aIZv_A.png" alt=""&gt;&lt;/a&gt;Screenshot of terminal that connected to EC2 instance and started a Python web server. In the background is the browser, that connects to the same EC2 instance and successfully displays the hosted website.&lt;/p&gt;

&lt;p&gt;If everything works out as planned we are able to SSH into the virtual machine and start a web server. Connecting to the same IP address using the browser should then result in the expected website.&lt;/p&gt;

&lt;p&gt;Awesome, we just created a CloudFormation stack! It’s time to celebrate 🥳&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WYoEyM_t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://media1.tenor.com/images/416e281b1accd222c98e33d7a3126f01/tenor.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WYoEyM_t--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://media1.tenor.com/images/416e281b1accd222c98e33d7a3126f01/tenor.gif" alt="Alt text of image"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Delete the stack
&lt;/h4&gt;

&lt;p&gt;After a celebration we need to do the boring, but necessary part — we need to clean our &lt;em&gt;mess&lt;/em&gt; up. Fortunately it’s fairly easy, so that when we’re done testing and playing around we can just delete the stack. Removing the stack will clean up the virtual machine, including all other provisioned resources.&lt;a href="https://us-west-1.console.aws.amazon.com/cloudformation/home"&gt;Navigate to the CloudFormation service&lt;/a&gt;, select the stack and click “Delete”. This will delete all related resources. Refresh the event section after a little bit to make sure the deletion completed successfully.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Tip: Check into the &lt;a href="https://console.aws.amazon.com/billing/home"&gt;billing and cost management section of AWS Console&lt;/a&gt; 1–2 days later and verify that no unexpected charges are accruing. Unfortunately it doesn’t seem to be possible to see real-time charge-updates.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Conclusion
&lt;/h4&gt;

&lt;p&gt;There you have it, a virtual machine provisioned through CloudFormation. It configured everything from virtual machine, to the network to the IP address.&lt;/p&gt;

&lt;p&gt;However, CloudFormation allows us to do much more. Imagine provisioning a bunch of stacks like this for a particular application, we would still have to SSH into these machines and set up a web server or run whatever application we want manually. Wouldn’t it be great if we could automate that step as well, so that we don’t even need to SSH into any of the machines? CloudFormation can help us with that as well! In a future chapter I’ll dive into how we can further customize our YAML annotation to run our scripts, after we successfully spin up a virtual machine.&lt;/p&gt;

&lt;p&gt;Please let me know if you have questions, comments and if this short introduction to CloudFormation was helpful.&lt;/p&gt;

&lt;h4&gt;
  
  
  Sample Project
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/skofgar/cloudformation"&gt;https://gitlab.com/skofgar/cloudformation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  References
&lt;/h4&gt;

&lt;p&gt;AWS CloudFormation Documentation&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-anatomy.html#template-anatomy-sections"&gt;Template Structure / Anatomy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/template-reference.html"&gt;Template References&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/deploying.applications.html"&gt;Deploying Applications&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Others&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.observian.com/blog/aws-cloudformation-101-introduction"&gt;CloudFormation 101&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Thanks
&lt;/h4&gt;

&lt;p&gt;Thanks to my coworker Alexandra for reviewing and giving me feedback on this article.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://skofgar.ch/dev/2020/11/deploying-a-vm-using-aws-cloud-formation/"&gt;&lt;em&gt;Skofgar’s Blog&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>cloud</category>
      <category>howto</category>
      <category>amazon</category>
      <category>cloudformation</category>
    </item>
    <item>
      <title>Git: How to replace the master branch</title>
      <dc:creator>Roland 🐺</dc:creator>
      <pubDate>Mon, 31 Aug 2020 02:00:06 +0000</pubDate>
      <link>https://dev.to/skofgar/git-how-to-replace-the-master-branch-579a</link>
      <guid>https://dev.to/skofgar/git-how-to-replace-the-master-branch-579a</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ABpMbk_L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A50jS7b0YUeLZ-DNb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ABpMbk_L--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2A50jS7b0YUeLZ-DNb.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It happens to all of us, we accidentally commit something into a git repo that we didn’t mean to, even worse we also pushed it to the main repository on GitLab or GitHub.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;TL;DR — &lt;em&gt;too long; didn’t read&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Replace the current “&lt;em&gt;master&lt;/em&gt;” branch with another “&lt;em&gt;backup&lt;/em&gt;” branch.&lt;/p&gt;

&lt;p&gt;Local: git branch -f master backup&lt;/p&gt;

&lt;p&gt;Remote: git push origin +backup:master&lt;/p&gt;

&lt;p&gt;via: &lt;a href="https://stackoverflow.com/a/30106024/756976"&gt;StackOverflow&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Why does it matter if we commit undesired content into a repository?
&lt;/h4&gt;

&lt;p&gt;Good question. We use git to keep track of our source code, facilitate collaboration and preserve how the project evolved to the current state. Having the history at our fingertips is helpful when developing new features or trying to understand a specific section in the code — granted having &lt;a href="https://dev.to/innovationincu/how-to-write-a-useful-commit-message-a-git-guide-5c8e"&gt;meaningful commit statements&lt;/a&gt; is important.&lt;/p&gt;

&lt;p&gt;However there are a few things we &lt;strong&gt;do not&lt;/strong&gt; want to track in git. This can entail, but is not limited to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;temporary files&lt;/li&gt;
&lt;li&gt;the built software (binaries, executables, …)&lt;/li&gt;
&lt;li&gt;personal information&lt;/li&gt;
&lt;li&gt;credentials&lt;/li&gt;
&lt;li&gt;proprietary information&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sensitive information that could accidentally or unknowingly be committed to the repository, like personal information, credentials and proprietary information may be harmful to the business should the information ever be leaked. This applies to public and private repositories — please note that even private repositories are affected, since they sometimes become public or get accessed by various people.&lt;/p&gt;

&lt;h4&gt;
  
  
  Can’t I just undo the change or roll back to a previous commit?
&lt;/h4&gt;

&lt;p&gt;If you already pushed it to the &lt;em&gt;master&lt;/em&gt; branch of your project, it will likely be too late. Even reverting a commit or committing an updated version where the undesired information is removed, will still leave traces in the git history.&lt;/p&gt;

&lt;h4&gt;
  
  
  Strategies on how to remove unwanted information
&lt;/h4&gt;

&lt;p&gt;Here are a few strategies, depending how big of a correction is needed:&lt;/p&gt;

&lt;p&gt;L1 — committing unwanted information to a local branch&lt;/p&gt;

&lt;p&gt;Committing to a local branch is the easiest step to resolve, you can either &lt;a href="https://www.atlassian.com/git/tutorials/rewriting-history"&gt;&lt;em&gt;amend&lt;/em&gt;&lt;/a&gt; the lastest commit and remove the undesired changes, or branch off from the previous commit and then delete the erroneous branch.&lt;/p&gt;

&lt;p&gt;L2 — pushing unwanted commits to a shared repository, feature branch&lt;/p&gt;

&lt;p&gt;As soon as commits are pushed to a shared (origin/remote) repository, things get tricky. If it is a &lt;a href="https://jeffkreeftmeijer.com/git-flow/"&gt;feature branch&lt;/a&gt; or any other non-main (aka &lt;em&gt;master&lt;/em&gt;) branch follow these steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Notify anyone that might be collaborating on this branch, that they should refrain from pushing/pulling&lt;/li&gt;
&lt;li&gt;Follow the L1 steps and create a new branch that contains only the commits &lt;em&gt;before&lt;/em&gt; the erroneous commit.&lt;/li&gt;
&lt;li&gt;Push the new branch and delete the erroneous branch locally and on the shared repository&lt;/li&gt;
&lt;li&gt;Optional: rename the new branch to have the same name as the original branch&lt;/li&gt;
&lt;li&gt;Notify colleagues to resume work as usual&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;L3 — pushing unwanted commits to a shared repository, main branch&lt;/p&gt;

&lt;p&gt;This is one gets very nerve wracking to resolve. Main branches could be any branches that are either production or development-sensitive. Often their names contain words like &lt;em&gt;master, development&lt;/em&gt; or &lt;em&gt;release&lt;/em&gt;, but this depends on the practices of your team.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Notify your the project lead and your coworkers that are actively working on the project to stop pulling and pushing to the main branch&lt;/li&gt;
&lt;li&gt;If you have a Continuous Integration and Continuous Deployment (CI/CD) pipeline running, check with your colleagues if it has to be paused or active jobs have to be aborted&lt;/li&gt;
&lt;li&gt;Follow the L1 steps and create a new branch that contains only the commits &lt;em&gt;before&lt;/em&gt; the erroneous commit.&lt;/li&gt;
&lt;li&gt;Replace the main “&lt;em&gt;master&lt;/em&gt;” branch with the “&lt;em&gt;fixed&lt;/em&gt; “branch using:
git push origin +fixed:master
Depending on what your remote repository is named you might need to replace &lt;em&gt;origin&lt;/em&gt;. However &lt;em&gt;remote&lt;/em&gt; and &lt;em&gt;origin&lt;/em&gt; are frequent default values&lt;/li&gt;
&lt;li&gt;Notify the project lead and coworkers to resume work and reactivate any suspended CI/CD pipelines&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;L4 — accidentally rewriting the history of a main branch&lt;/p&gt;

&lt;p&gt;What if a branch gets merged into a main branch that contains a lot of undesired commits and changes? For example an experimental branch. Merging a lot of changes into a main branch may rewrite a lot of the git history and make going back to a previous commit and re-applying changes too tedious and practically impossible to fix.&lt;/p&gt;

&lt;p&gt;Fear not! There might still be ways to salvage this. Check the following places:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Do you have a local copy or a very recent branch/fork of the main branch that could be used — even if it needed a few edits&lt;/li&gt;
&lt;li&gt;Most backup softwares usually do hourly backups and might have an older version of the branch in question that could be restored&lt;/li&gt;
&lt;li&gt;Coworkers might haven’t pulled the latest main branch yet or a branch that is only minimally diverged from the original main branch. Get a copy from them and re-apply — if needed — the latest commits&lt;/li&gt;
&lt;li&gt;If nothing works you could explore using the &lt;a href="https://rtyley.github.io/bfg-repo-cleaner/"&gt;BFG Repo-Cleaner&lt;/a&gt; to scrub the project from sensitive information. However, using the tool is very tedious and the history might still not be completely clean. Furthermore, it will result in creating a new repository and having everyone switch over to that one&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Hopefully a backup can be found and the main branch can be restored by following the steps outlined in L3.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pLOukpTV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/500/0%2A59k-m4-HsP1dGHc-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pLOukpTV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/500/0%2A59k-m4-HsP1dGHc-.png" alt="Humorous book cover about the joy of pushing to master, using irony implying pushing to master is always ok"&gt;&lt;/a&gt;Humorous: The joy of pushing to master&lt;/p&gt;

&lt;h4&gt;
  
  
  How can we prevent accidental merges from happening in the future?
&lt;/h4&gt;

&lt;p&gt;It is good to know that we can fix these mistakes, but the approaches covered earlier are tedious and nerve wracking. There must be better ways to prevent these mishaps from occurring in the first place?&lt;/p&gt;

&lt;p&gt;Fortunately there are ways to reduce the risk of accidentally committing into the most sensitive branches. Let me suggest the following actions:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Do not push to main branches&lt;/strong&gt; directly — 
This is the most obvious takeaway. Never push directly to a main branch. We’ve all done it and we’ve told others not to do it. It happens to me too and I had to fix main branches in the past&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Use a branching model&lt;/strong&gt; like &lt;a href="https://jeffkreeftmeijer.com/git-flow/"&gt;Git-Flow&lt;/a&gt; or &lt;a href="https://docs.gitlab.com/ee/topics/gitlab_flow.html"&gt;GitLab Flow&lt;/a&gt;. These approaches are detailed and even using a customized variation that works for you and your team is possible and worthwhile&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protect important branches&lt;/strong&gt;  — see &lt;a href="https://docs.gitlab.com/ee/user/project/protected_branches.html"&gt;GitLab protected branches&lt;/a&gt; and &lt;a href="https://docs.github.com/en/github/administering-a-repository/about-protected-branches"&gt;GitHub protected branches&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Have &lt;a href="https://docs.gitlab.com/ee/development/code_review.html"&gt;merge-request &lt;strong&gt;reviews&lt;/strong&gt;&lt;/a&gt; (or pull requests for GitHub)&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;secret detection&lt;/strong&gt;  — tools like GitLab support &lt;a href="https://docs.gitlab.com/ee/user/application_security/secret_detection/#configuration"&gt;secret detection&lt;/a&gt; and security scanning&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Conclusion
&lt;/h4&gt;

&lt;p&gt;Protecting the main branches like &lt;em&gt;master&lt;/em&gt; and establishing a workflow entailing review processes in order to get commits into these important branches helps prevent accidental commits including secrets, sensitive information and errors. Even with this model it is still possible, that mistakes can happen and we learned ways on how we can remedy undesired commits, how to replace entire branches and how sensitive information can be removed.&lt;/p&gt;

&lt;p&gt;Please let all of us know in the comments below what other approaches there are, which ones worked for you and share your &lt;em&gt;scary&lt;/em&gt; git stories with us.&lt;/p&gt;

&lt;h4&gt;
  
  
  References
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/30105210/git-overwrite-master-with-branch"&gt;Stackoverflow: How to replace a branch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rtyley.github.io/bfg-repo-cleaner/"&gt;BFG Repo-Cleaner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/innovationincu/how-to-write-a-useful-commit-message-a-git-guide-5c8e"&gt;How to Write a useful Commit Message: A Git Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://about.gitlab.com/blog/2018/06/07/keeping-git-commit-history-clean/"&gt;GitLab: How (and why!) to keep your Git commit history clean&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jeffkreeftmeijer.com/git-flow/"&gt;Git branching: Git-Flow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.gitlab.com/ee/topics/gitlab_flow.html"&gt;Git branching: GitLab-Flow&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://skofgar.ch/dev/2020/08/git-how-to-replace-the-master-branch/"&gt;&lt;em&gt;Skofgar’s Blog&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gitflow</category>
      <category>gitlab</category>
      <category>softwaredevelopment</category>
      <category>gitlabflow</category>
    </item>
    <item>
      <title>How to quickly replace environment variables in a file</title>
      <dc:creator>Roland 🐺</dc:creator>
      <pubDate>Sun, 23 Aug 2020 03:53:02 +0000</pubDate>
      <link>https://dev.to/skofgar/how-to-quickly-replace-environment-variables-in-a-file-359g</link>
      <guid>https://dev.to/skofgar/how-to-quickly-replace-environment-variables-in-a-file-359g</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wS7YXNn1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AD3l-Hk66J03OOCyD.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wS7YXNn1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AD3l-Hk66J03OOCyD.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We know storing credentials or other sensitive values in a configuration file (e.g. Kubernetes yaml file) is bad, but how can we get values easily replaced without having to do a complicated string substitution or writing a custom Python script?&lt;/p&gt;

&lt;p&gt;I often have personal environment variable files for projects that I use to store credentials and configurations in. Before working on a project I would the corresponding configuration file into the shell session. However, these files cannot be stored in git repositories or shared with coworkers or bots. Even worse, sometimes the repositories have files in them that need to be changed, which is dangerous, because it’s easy to accidentally commit these files.&lt;/p&gt;

&lt;p&gt;Well as it turns out, there already is a good solution and it is called envsubst. We can use envsubst to substitute environment variable placeholders inside configuration files and we can even pipe it into other commands like Kubernetes' kubectl.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;envsubst &amp;lt; config.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  EnvSubst
&lt;/h4&gt;

&lt;p&gt;The &lt;a href="https://www.gnu.org/software/gettext/manual/gettext.html#envsubst-Invocation"&gt;envsubst&lt;/a&gt; is part of the &lt;a href="https://www.gnu.org/software/gettext/"&gt;gettext&lt;/a&gt; internationalization (i18n) and localization (l10n) project for unix. It's usage is quite easy and I hope this will explain it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Some systems have gettext with envsubst preinstalled. However, if it is missing, you can install it using a package manager. For macOS you can use &lt;em&gt;homebrew:&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;brew install gettext&lt;/p&gt;

&lt;p&gt;Learn more about homebrew in &lt;a href="https://skofgar.ch/computer-science/2020/04/setting-up-your-dev-machine-in-one/"&gt;my article about setting about your development machine in one script&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Example
&lt;/h4&gt;

&lt;p&gt;Let’s say, we have an existing configuration file, that want to give to someone or use with a bot. Ideally we don’t want to include credentials in that file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# my configuration file
server: https://gitlab.com/skofgar
username: foo_user
password: mymonkey
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  1. Create sample configuration file
&lt;/h4&gt;

&lt;p&gt;We don’t want to check that information into a git repository nor do we want it laying around or send it to someone like this , but how can we improve this? Lets replace the information we don’t want in the file with environment variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;server: $SERVER_URL
username: $USER_NAME
password: $USER_PASSWORD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  2. Configure environment variables
&lt;/h4&gt;

&lt;p&gt;Then define these environment variables either by defining them in the shell session with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export SERVER_URL=https://gitlab.com/skofgar
export USER_NAME=foo_user
export USER_PASSWORD=mymonkey
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or save them to a file (e.g. .env) and then loading them into your current shell session by using source .env&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Make sure to use export, otherwise your variables are considered &lt;em&gt;shell&lt;/em&gt; variables and might not be accessible to envsubst&lt;/p&gt;

&lt;p&gt;Read more here: &lt;a href="https://ostechnix.com/difference-between-defining-bash-variables-with-and-without-export/"&gt;https://ostechnix.com/difference-between-defining-bash-variables-with-and-without-export/&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  3. Substitution
&lt;/h4&gt;

&lt;p&gt;To run an actual substitution, perform the following commands.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; envsubst &amp;lt; config.txt  
server: https://gitlab.com/skofgar
username: foo_user
password: mymonkey
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is also possible to write your substitution to a new file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; envsubst &amp;lt; config.txt &amp;gt; confidential_config.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Piping substitution into Kubernetes and other tools
&lt;/h4&gt;

&lt;p&gt;It is possible to pipe the output into other commands like less or kubectl for Kubernetes (k8s).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# pipe into less
&amp;gt; envsubst &amp;lt; config.txt | less

# pipe a deployment "deploy.yml" into kubectl apply
&amp;gt; envsubst &amp;lt; deploy.yml | kubectl apply -f -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Conclusion
&lt;/h4&gt;

&lt;p&gt;This is a great way to improve your &lt;em&gt;Continuous Integration and Continuous Deployment (CI/CD)&lt;/em&gt; pipelines or just simplify your own workflow. I use this for a project where we have to replace credentials that are temporarily needed, that we didn’t want to check into the git repository and that a CI pipeline also needs to access.&lt;/p&gt;

&lt;p&gt;Let me know in the comments what you think of this solution and if you have come across an alternative approach.&lt;/p&gt;

&lt;p&gt;Here’s a summary of all steps combined:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# print content of configuration file
&amp;gt; cat config.txt
server: $SERVER_URL
username: $USER_NAME
password: $USER_PASSWORD

# load environment variables
&amp;gt; source .env

# replace environment variables in file content
&amp;gt; envsubst &amp;lt; config.txt
server: https://gitlab.com/skofgar
username: foo_user
password: mymonkey

# replace environment variables and write to new file
&amp;gt; envsubst &amp;lt; config.txt &amp;gt; confidential_config.txt

# pipe into less
&amp;gt; envsubst &amp;lt; config.txt | less

# pipe a deployment "deploy.yml" into kubectl apply
&amp;gt; envsubst &amp;lt; deploy.yml | kubectl apply -f -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Sources
&lt;/h4&gt;

&lt;p&gt;Some of the sources I used for this article are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;envsubst for Kubernetes: &lt;a href="https://serverfault.com/a/843883"&gt;https://serverfault.com/a/843883&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;gettext documentation: &lt;a href="https://www.gnu.org/software/gettext/"&gt;https://www.gnu.org/software/gettext/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://skofgar.ch/dev/2020/08/how-to-quickly-replace-environment-variables-in-a-file/"&gt;&lt;em&gt;Skofgar’s Blog&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>environmentvariables</category>
      <category>envsubst</category>
      <category>k8s</category>
    </item>
    <item>
      <title>Prefix CLI output</title>
      <dc:creator>Roland 🐺</dc:creator>
      <pubDate>Mon, 22 Jun 2020 03:05:03 +0000</pubDate>
      <link>https://dev.to/skofgar/prefix-cli-output-58fd</link>
      <guid>https://dev.to/skofgar/prefix-cli-output-58fd</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yCnTRSz8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AcF2d229hNmp8WWEf.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yCnTRSz8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/0%2AcF2d229hNmp8WWEf.jpeg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When interacting with the command line or writing automated scripts it’d be useful to prefix the output with the date or something equivalently useful. If you are a Linux or Terminal user you’ve probably come across the pipe symbol | , which for example allows you to apply grep filters, but it is not entirely clear how to prefix constant strings or dynamically evaluated commands like the &lt;em&gt;date&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;The following example shows how you’d use the pipe to filter multiple lines, to find a specific keyword&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; echo -e "Lorem ipsum dolor\nfoo\nbar"
Lorem ipsum dolor
foo
bar

&amp;gt; echo -e "Lorem ipsum dolor\nfoo\nbar" | grep foo
foo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Prefix string
&lt;/h4&gt;

&lt;p&gt;Similarly you can add text before or append text to each line using the &lt;a href="https://tldr.ostera.io/sed"&gt;&lt;em&gt;sed&lt;/em&gt; text substitution command&lt;/a&gt;. The general structure of the command is ‘s/textToReplace/replaceWithThis/‘. However, we’re not substituting anything, instead we instruct it to &lt;em&gt;prefix&lt;/em&gt; using the carot symbol ^.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# prefix with "Hello "
&amp;gt; echo World | sed 's/^/Hello /' 
Hello World
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Prefix computed value
&lt;/h4&gt;

&lt;p&gt;It is possible to prefix a dynamically evaluated command. To do so we need to add an evaluated string to our string replacement &lt;em&gt;sed&lt;/em&gt; command. First, open the &lt;em&gt;sed&lt;/em&gt; command by using single quotes, then we need to wrap the command we want to evaluate in double- and single-quotes "&lt;code&gt;COMMAND&lt;/code&gt;" .&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Single, double and back-tick quotes?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;single quotes&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
retain literal value of each single character inside&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;double quotes&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
retain literal content except content that will be evaluated, like dollar signs or back-ticks&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;back ticks&lt;/em&gt;&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
an older style to trigger evaluation of it’s content. Nowadays the use of $( ) is more common&lt;/p&gt;

&lt;p&gt;More information about quote types can be found: on &lt;a href="https://stackoverflow.com/a/6697781/756976"&gt;this Stackoverflow post&lt;/a&gt;; information about &lt;a href="https://unix.stackexchange.com/a/5782"&gt;backticks&lt;/a&gt;; the &lt;a href="http://www.gnu.org/software/bash/manual/html_node/Single-Quotes.html"&gt;single&lt;/a&gt; and &lt;a href="http://www.gnu.org/software/bash/manual/html_node/Double-Quotes.html"&gt;double quotes gnu docs&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# example on how to insert a `COMMAND`
&amp;gt; echo World | sed 's/^/'"`COMMAND`"'/'
         literal value / | \ evaluate 
                  retain content

# equivalent $( ) command
&amp;gt; echo World | sed 's/^/'"$(COMMAND)"'/'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For improved readability I will use $( ) instead of back ticks.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# prefix with "Hello " and date
&amp;gt; echo World | sed 's/^/'"$(date)"' Hello /'
So 21 Jun 2020 22:21:39 MDT Hello World

# prefix with "Hello " and ISO 8601 date
&amp;gt; echo World | sed 's/^/'"$(date -u +"%Y-%m-%dT%H:%M:%SZ") "'Hello /' 
2020-06-22T04:16:04Z Hello World
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Please note that the date is formatted with &lt;a href="https://en.wikipedia.org/wiki/ISO_8601"&gt;ISO 8601&lt;/a&gt;. I highly recommend that you consider formatting all dates with this standard, because you will do your future self or everyone else a favor by knowing what time formatting you used!&lt;br&gt;&lt;br&gt;
date -u +"%Y-%m-%dT%H:%M:%SZ"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  TL;DR
&lt;/h4&gt;

&lt;p&gt;To sum up, using the example above, we can use the pipe and the &lt;em&gt;sed&lt;/em&gt; command to prefix each line with the date and “Hello “&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; echo -e "Lorem ipsum dolor\nfoo\nbar" | sed 's/^/'"$(date -u +"%Y-%m-%dT%H:%M:%SZ") "'Hello /'
2020-06-22T05:00:34Z Hello Lorem ipsum dolor
2020-06-22T05:00:34Z Hello foo
2020-06-22T05:00:34Z Hello bar
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let me know if you find this useful or please share any alternative ways to prefix.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://skofgar.ch/dev/2020/06/prefix-cli-output/"&gt;&lt;em&gt;Skofgar’s Blog&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>developer</category>
      <category>date</category>
      <category>cli</category>
      <category>bash</category>
    </item>
    <item>
      <title>Setting up your DEV machine in ONE script</title>
      <dc:creator>Roland 🐺</dc:creator>
      <pubDate>Fri, 03 Apr 2020 00:37:01 +0000</pubDate>
      <link>https://dev.to/skofgar/setting-up-your-dev-machine-in-one-script-2po7</link>
      <guid>https://dev.to/skofgar/setting-up-your-dev-machine-in-one-script-2po7</guid>
      <description>&lt;p&gt;A new computer is great 💻🎉 — It’s a clean slate. It’s snappy. It’s great… but it is missing all the tools I rely on every day! My work requires me to jump around in a variety of tools and technology stacks, hence I need to install a lot of different tools and be able to support different development environments.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ljwrcpZn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ABJIYUB5WjmIomJlmkz5Big.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ljwrcpZn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2ABJIYUB5WjmIomJlmkz5Big.jpeg" alt=""&gt;&lt;/a&gt;Photo by Claude Piché on Unsplash&lt;/p&gt;

&lt;h4&gt;
  
  
  Existing package manager for CLI tools
&lt;/h4&gt;

&lt;p&gt;Over time developers load command-line tools like people are buying toilet paper these days. From &lt;strong&gt;maven&lt;/strong&gt; , via &lt;strong&gt;tl;dr&lt;/strong&gt; , stopping at &lt;strong&gt;kubectl&lt;/strong&gt; to &lt;strong&gt;tmux&lt;/strong&gt;. We use all of those little nifty tools. Hence setting up a new machine can seem scary task at times, &lt;strong&gt;but fear not&lt;/strong&gt;! For CLI tools we solved that problem long long ago with &lt;a href="https://brew.sh"&gt;Homebrew&lt;/a&gt;, or as you probably know it: &lt;em&gt;brew&lt;/em&gt;&lt;br&gt;&lt;br&gt;
&lt;em&gt;(The windows folks probably know&lt;/em&gt; &lt;a href="https://chocolatey.org"&gt;&lt;em&gt;Chocolatey&lt;/em&gt;&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;You can install maven for example by running: brew install maven&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Fear not! The same tool that installs CLI tools can install (almost) all our applications!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;
  
  
  Brew can do more!
&lt;/h4&gt;

&lt;p&gt;Homebrew uses &lt;a href="https://formulae.brew.sh"&gt;formulae&lt;/a&gt; (or recipes) to install the tools you need in it’s &lt;em&gt;Cellar&lt;/em&gt;. However, it can &lt;em&gt;tap&lt;/em&gt; into its &lt;em&gt;casks&lt;/em&gt; if you need Slack, Atom, Visual Studio Code, Java, 1Password or SourceTree — enough with the puns! It’s literally as easy as installing a CLI package.&lt;/p&gt;

&lt;p&gt;You probably heard about casks or seen it fly by in the console.. let’s look at an example. Let’s say you want to install Firefox using brew. All you need to type is:&lt;/p&gt;

&lt;p&gt;brew cask install firefox&lt;/p&gt;

&lt;p&gt;Brew will update its formulae, look for the application you want to install and do it right away.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; brew cask install firefox
Updating Homebrew...
==&amp;gt; Auto-updated Homebrew!
Updated 2 taps (homebrew/core and homebrew/cask).
==&amp;gt; Updated Formulae
abcmidi cataclysm contentful-cli llvm logtalk
==&amp;gt; Updated Casks
google-chrome           

==&amp;gt; Downloading https://download-installer.cdn.mozilla.net/pub/firefox/releases/
######################################################################## 100.0%
==&amp;gt; Verifying SHA-256 checksum for Cask 'firefox'.
==&amp;gt; Installing Cask firefox
==&amp;gt; Moving App 'Firefox.app' to '/Applications/Firefox.app'.
🍺 firefox was successfully installed!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Brew can’t install my application!
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; brew cask install xcode                         
Updating Homebrew...
Error: Cask 'xcode' is unavailable: No Cask with this name exists. Did you mean “swiftformat-for-xcode”?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately not every app has a recipe on homebrew. However, you may just don’t know the correct name or have spelt it incorrectly. To double-check there is a useful brew search THE-THING-I'M-LOOKING-FOR and as long as it's not cat-pictures, you'll likely be successful.&lt;/p&gt;

&lt;p&gt;In docker’s case, it will even give you formulae’s and casks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; brew search docker                                                  
==&amp;gt; Formulae
docker docker-machine-driver-vmware
docker-clean docker-machine-driver-vultr
docker-completion docker-machine-driver-xhyve
docker-compose docker-machine-nfs
docker-compose-completion docker-machine-parallels
docker-credential-helper docker-slim
docker-credential-helper-ecr docker-squash
docker-gen docker-swarm
docker-ls docker2aci
docker-machine dockerize
docker-machine-completion lazydocker
docker-machine-driver-hyperkit
==&amp;gt; Casks
docker homebrew/cask-versions/docker-edge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Ok, we get it, but where is that single script?
&lt;/h4&gt;

&lt;p&gt;Ok… I’ve digressing about brew. To create a single &lt;em&gt;setup&lt;/em&gt; script, it also needs to be able to install homebrew itself. Fortunately, that’s easy and available directly from brew’s website &lt;a href="https://brew.sh"&gt;https://brew.sh&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I combined everything I mentioned in a sample script, that I use myself:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gitlab.com/snippets/1961907"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--b1icV5fM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/1024/1%2A13gLd10hMLVDXGO435A5ww.png" alt=""&gt;&lt;/a&gt;An example script for brew using formulae and casks&lt;/p&gt;

&lt;p&gt;This drastically reduced the amount of time to set up my environment (about 25 min, depending on internet connection) and will make it easier in the future, if I decide to rebuild the machine.&lt;/p&gt;

&lt;h4&gt;
  
  
  Potential improvements
&lt;/h4&gt;

&lt;p&gt;Here are a few improvement ideas:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identifying all the casks that require password and moving them at the beginning would simplify this script&lt;/li&gt;
&lt;li&gt;Further improve the script to do all additional customization (desktop, os settings, …)&lt;/li&gt;
&lt;li&gt;If you always work on the same projects, creating and executing a script with git clones and creating all the environments might be a good next step&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you find this article interesting and please let me know if you have any questions.&lt;/p&gt;

&lt;h4&gt;
  
  
  Resources
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Formulaes Overview: &lt;a href="https://formulae.brew.sh"&gt;https://formulae.brew.sh&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Formulaes for CLI Packages: &lt;a href="https://formulae.brew.sh/formula/"&gt;https://formulae.brew.sh/formula/&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Casks: &lt;a href="https://formulae.brew.sh/cask/"&gt;https://formulae.brew.sh/cask/&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="https://skofgar.ch/computer-science/2020/04/setting-up-your-dev-machine-in-one/"&gt;&lt;em&gt;Skofgar’s Blog&lt;/em&gt;&lt;/a&gt;&lt;em&gt;.&lt;/em&gt;&lt;/p&gt;




</description>
      <category>softwareengineering</category>
      <category>productivity</category>
      <category>softwaredevelopment</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
