<?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: Jan Egil Ring</title>
    <description>The latest articles on DEV Community by Jan Egil Ring (@janegilring).</description>
    <link>https://dev.to/janegilring</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%2F522002%2F2c089c39-92bb-477b-9e7b-bae9689edec8.jpeg</url>
      <title>DEV Community: Jan Egil Ring</title>
      <link>https://dev.to/janegilring</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/janegilring"/>
    <language>en</language>
    <item>
      <title>Introduction to Red Hat OpenShift Container Platform</title>
      <dc:creator>Jan Egil Ring</dc:creator>
      <pubDate>Mon, 01 Aug 2022 14:55:00 +0000</pubDate>
      <link>https://dev.to/janegilring/introduction-to-red-hat-openshift-container-platform-2a5d</link>
      <guid>https://dev.to/janegilring/introduction-to-red-hat-openshift-container-platform-2a5d</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Having worked with Kubernetes for some time, as well as Red Hat Enterprise Linux, I was eager to learn more about Red Hat's container product - Red Hat OpenShift Container Platform (OCP).&lt;/p&gt;

&lt;p&gt;It is part of Red Hat's containerisation software family OpenShift, and based on Kubernetes.&lt;/p&gt;

&lt;p&gt;In this post, I am going to share my perspectives based on my learnings so far.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture and core concepts
&lt;/h2&gt;

&lt;p&gt;Based on Kubernetes - the defacto standard for orchestrating containers - OpenShift Container Platform adds additional functionality and features.&lt;br&gt;
It is based on Red Hat Enterprise Linux CoreOS as the foundational operating system for the control plane and worker nodes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m4mbHAXT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/janegilring/janegilring.github.io/blob/master/images/2022-07-31-rh-ocp-architecture.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m4mbHAXT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/janegilring/janegilring.github.io/blob/master/images/2022-07-31-rh-ocp-architecture.png%3Fraw%3Dtrue" alt="alt" width="880" height="709"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image credit: &lt;a href="https://docs.openshift.com/container-platform/4.10/welcome/oke_about.html"&gt;Red Hat&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Just like Kubernetes, it supports deployment to a variety of targets:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Physical servers&lt;/li&gt;
&lt;li&gt;Virtual machines&lt;/li&gt;
&lt;li&gt;Private Cloud&lt;/li&gt;
&lt;li&gt;Public Cloud&lt;/li&gt;
&lt;li&gt;Edge&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The deployment process for manual installations might be more complex compared to the other options. Ben Weissman have a course on Pluralsight I can recommend - &lt;a href="https://app.pluralsight.com/library/courses/openshift-getting-started/table-of-contents"&gt;Getting Started with OpenShift 4&lt;/a&gt;, which goes through the requried steps.&lt;/p&gt;

&lt;p&gt;The easiest way to get started is probably using a public cloud offering, such as &lt;a href="https://azure.microsoft.com/en-us/services/openshift/#overview"&gt;Azure Red Hat OpenShift&lt;/a&gt; - a highly available, fully managed OpenShift cluster on demand, monitored and operated jointly by Microsoft and Red Hat.&lt;/p&gt;

&lt;p&gt;The lifecycle of a Red Hat OCP cluster is described by Red Hat as follows:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--42QvsFRs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/janegilring/janegilring.github.io/blob/master/images/2022-07-31-rh-ocp-lifecycle.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--42QvsFRs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/janegilring/janegilring.github.io/blob/master/images/2022-07-31-rh-ocp-lifecycle.png%3Fraw%3Dtrue" alt="alt" width="880" height="314"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image credit: &lt;a href="https://docs.openshift.com/container-platform/4.10/welcome/oke_about.html"&gt;Red Hat&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When a cluster has been provisioned and is ready for use by developers - which we may see as the users of a clusters - Red Hat OCP have a lof of features making it easier to get started with less plumbing required as we can see in the following section.&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Console
&lt;/h3&gt;

&lt;p&gt;A web-based interface provided by the Red Hat OCP cluster that allows developers and administrators to interact with cluster resources.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zD8vIRVZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/janegilring/janegilring.github.io/blob/master/images/2022-07-31-rh-ocp-web-console.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zD8vIRVZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/janegilring/janegilring.github.io/blob/master/images/2022-07-31-rh-ocp-web-console.jpg%3Fraw%3Dtrue" alt="alt" width="880" height="716"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Project
&lt;/h3&gt;

&lt;p&gt;An OpenShift extension of Kubernetes' namespaces, which allows the definition of user access control to cluster resources - providing an application or workload isolation from other resources in the same cluster.&lt;/p&gt;

&lt;h3&gt;
  
  
  Networking
&lt;/h3&gt;

&lt;p&gt;As with Kubernetes - the concept of services enables network access internally between pods in a cluster - and acts as an abstration layer on top of pods and deployments.&lt;/p&gt;

&lt;p&gt;External access is provided by resources called Routes. A route is an object describing DNS names and ports external to the cluster (potentially the internet) pointing to a service inside the cluster.&lt;br&gt;
A router (the same as an ingress controller) is responsible for forwarding requests (HTTP and TLS) to the service addresses inside the Kubernetes SDN.&lt;/p&gt;

&lt;p&gt;OpenShift is by default leveraging &lt;a href="https://en.wikipedia.org/wiki/HAProxy"&gt;HAProxy&lt;/a&gt; as its router.&lt;/p&gt;

&lt;p&gt;OpenShift relays on a wildcard DNS domain for exposing applications outside of the cluster. When installing a cluster, a name and a base DNS domain is provided. Both of these are used in the wildcard DNS domain for exposing applications:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;*.apps.&amp;lt;cluster_name&amp;gt;.&amp;lt;base_domain&amp;gt;.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;*.apps.ocp.powershell.no&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When exposing services as routes, the naming convention &lt;em&gt;route-name-project-name.default-domain&lt;/em&gt; is used:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;oc expose service wordpress&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;However, this can be overriden if needed:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;oc expose service wordpress --name blog&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The routes can also be managed via the Web Console if desired:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iLnlcgc3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/janegilring/janegilring.github.io/blob/master/images/2022-07-31-rh-ocp-web-console-02.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iLnlcgc3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/janegilring/janegilring.github.io/blob/master/images/2022-07-31-rh-ocp-web-console-02.jpg%3Fraw%3Dtrue" alt="alt" width="880" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Registry
&lt;/h3&gt;

&lt;p&gt;As oposed to Kubernetes, Red Hat OCP by default provides an internal container registry for storing and pulling container images from - eliminating the need for provisioning a registry ourselfes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Continuous integration and continuous delivery
&lt;/h3&gt;

&lt;p&gt;Part of Red Hat OCP is OpenShift Pipelines, a continuous integration and continuous delivery (CI/CD) solution based on Kubernetes resources. It uses &lt;a href="https://tekton.dev"&gt;Tekton&lt;/a&gt; building blocks to automate builds and deployments, which is running in isolated containers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Source-to-Image (S2I)
&lt;/h3&gt;

&lt;p&gt;This is a tool to make it possible for developers to deploy their applications from source code - without needing any knowledge about Dockerfiles or container images.&lt;/p&gt;

&lt;p&gt;Built on a base image - code from a specified Git repository is injected into image and a new image which can run the application is produced by a build pipeline. Several pre-built base images is available, and one may choose based on the language or framework being used in the application being built.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vDxuvBz6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/janegilring/janegilring.github.io/blob/master/images/2022-07-31-rh-ocp-s2i.jpg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vDxuvBz6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/janegilring/janegilring.github.io/blob/master/images/2022-07-31-rh-ocp-s2i.jpg%3Fraw%3Dtrue" alt="alt" width="751" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image credit: &lt;a href="https://cloud.redhat.com/blog/guide-to-openshift-pipelines-part-2-using-source-2-image-build-in-tekton"&gt;Red Hat&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although one might prefer to use traditional methods to build container images based on Dockerfiles, the S2I tool has a number of advantages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;When the base image has been patched, for example due to a critical security issue, the S2I pipeline can be triggered to rebuild the application image using the updated base image - without the need for any actions from the developer.&lt;/li&gt;
&lt;li&gt;No need for the developer to learn how to install required packages, such as yum install.&lt;/li&gt;
&lt;li&gt;There is a shared ecosystem of base images where customizations, scripts and other artifacts can be shared across organizations&lt;/li&gt;
&lt;li&gt;Efficiency - a large number of complex operations can be performed by the build process, resulting in smaller images with fewer layers.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When leveraging S2I, a BuildConfig where the source (typically a Git repository) is defined is being deployed in the current project along with an ImageStream to track the built images, a DeploymentConfig to create updated images when there are changes either to the base image or the source code, a Service to expose the application inside the cluster and optionally a Route to expose it externally.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Red Hat OpenShift Container Platform Command-line Tool
&lt;/h3&gt;

&lt;p&gt;While it is possible to use &lt;code&gt;kubectl&lt;/code&gt; to interact with the API server, the recommended way is to use oc command-line tool.&lt;/p&gt;

&lt;p&gt;Similar to the way &lt;code&gt;podman&lt;/code&gt; has mostly the same syntax and sub commands as &lt;code&gt;docker&lt;/code&gt;, &lt;code&gt;oc&lt;/code&gt; is very similar to &lt;code&gt;kubectl&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Examples of basic usage:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;oc &amp;lt;command&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;oc login &amp;lt;clusterUrl&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;oc get pods&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The main reason one should use &lt;code&gt;oc&lt;/code&gt; over &lt;code&gt;kubectl&lt;/code&gt; when working with Red Hat OCP clusters is being able to manage OCP-specific functionality.&lt;/p&gt;

&lt;p&gt;One of the most important ones being the &lt;code&gt;oc new-app&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;This command can create application pods to run on OpenShift in many different ways. It can create deployments from Docker images, from Dockerfiles, and from raw source code using the Source-to-Image (S2I) process as mentioned previously.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;oc new-app --help&lt;/code&gt; will show the different options available for creating new applications on OpenShift.&lt;/p&gt;

&lt;p&gt;Some examples:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;oc new-app --docker-image=registry.com/contoso/app1 --name=app1&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;oc new-app https://github.com/openshift/ruby-hello-world --name=ruby-hello&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Alternativly, all of the deployment options is also available in the OpenShift web console.&lt;/p&gt;

&lt;h3&gt;
  
  
  Operators
&lt;/h3&gt;

&lt;p&gt;Operators is a core Kubernetes concept, which is essentially a "Desired State" mechanism where a controller makes sure that the resources used by the managed application such as pods, services and persistent volumes are configured and running as desired. If not, the operator will take actions to remediate the issue. The Operators are also typically embedded with knowledge of the application by the vendor, so known issues can potentially be remediated without human involvement.&lt;/p&gt;

&lt;p&gt;Red Hat OCP leverages Operators to run its entire platform in an autonomous fashion while exposing the configuration through Kubernetes objects.&lt;/p&gt;

&lt;p&gt;Built-in is also an embedded OperatorHub, which contains multiple sources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Red Hat Operators - Red Hat products certified and supported by Red Hat&lt;/li&gt;
&lt;li&gt;Certified Operators - products packaged and supported by independent software vendors (ISVs)&lt;/li&gt;
&lt;li&gt;Community Operators - Operators from &lt;a href="https://github.com/operator-framework/community-operators"&gt;https://github.com/operator-framework/community-operators&lt;/a&gt; which can be optionally enabled&lt;/li&gt;
&lt;li&gt;Custom Operators - created by yourself&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Common infrastructure
&lt;/h3&gt;

&lt;p&gt;Management tools such as the console and API is part of a common Red Hat infrastucture.&lt;/p&gt;

&lt;p&gt;Building on the previous topic of Operators, Red Hat OpenShift Virtualization is a great example of leveraging common infrastructure. It is an Operator based on KubeVirt - a Kubernetes Virtualization technology that makes it possible to run and manage VMs side-by-side with containers. These VMs can be managed both as regular Kubernetes objects via the API as well as via the console:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9ZaoUZUz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/janegilring/janegilring.github.io/blob/master/images/2022-07-31-rh-ocp-vm-virtualization-02.jpeg%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9ZaoUZUz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/janegilring/janegilring.github.io/blob/master/images/2022-07-31-rh-ocp-vm-virtualization-02.jpeg%3Fraw%3Dtrue" alt="alt" width="880" height="379"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image credit: &lt;a href="https://www.redhat.com/en/technologies/cloud-computing/openshift/virtualization"&gt;Red Hat&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under the hood it is leveraging Linux Kernel-based Virtual Machine (KVM), a Linux Kernel hypervisor, within a container.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m7kR_bsB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/janegilring/janegilring.github.io/blob/master/images/2022-07-31-rh-ocp-vm-virtualization.png%3Fraw%3Dtrue" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m7kR_bsB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://github.com/janegilring/janegilring.github.io/blob/master/images/2022-07-31-rh-ocp-vm-virtualization.png%3Fraw%3Dtrue" alt="alt" width="880" height="310"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Image credit: &lt;a href="https://www.redhat.com/en/technologies/cloud-computing/openshift/virtualization"&gt;Red Hat&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This makes it possible to run both modernized container workloads and classic workloads which haven't or for some reason can't be containerized - in the same environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  Monitoring and logging
&lt;/h3&gt;

&lt;p&gt;Red Hat OCP includes a pre-configured, pre-installed, and self-updating monitoring stack that provides monitoring for core platform components. This is based on the Prometheus open source project and its wider eco-system.&lt;/p&gt;

&lt;p&gt;A set of alerts are included by default that can immediately notify cluster administrators about issues within a cluster. Default dashboards in the web console include visual representations of cluster metrics.&lt;/p&gt;

&lt;p&gt;It is also possible to enable monitoring for user-defined projects, but unlike the core cluster resources - this is not enabled by default.&lt;/p&gt;

&lt;h1&gt;
  
  
  Learning resources
&lt;/h1&gt;

&lt;p&gt;In order to get an understanding of Red Hat OCP, I went through the course &lt;a href="https://rol.redhat.com/rol/app/courses/do180vc-4.10"&gt;DO180 Red Hat OpenShift I: Containers &amp;amp; Kubernetes&lt;/a&gt;. This is highly recommended if you aim to get deeper knowledge and some hands-on experience.&lt;/p&gt;

&lt;p&gt;The goal for me in addition to getting hands-on experience was taking the &lt;a href="https://www.redhat.com/en/services/training/ex180-red-hat-certified-specialist-containers-kubernetes-exam?section=Overview"&gt;EX180 Red Hat Certified Specialist in Containers and Kubernetes exam&lt;/a&gt;, which has the following objectives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt; &lt;em&gt;Implement images using Podman&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt; &lt;em&gt;Understand and use FROM (the concept of a base image) instruction.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Understand and use RUN instruction.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Understand and use ADD instruction.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Understand and use COPY instruction.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Understand the difference between ADD and COPY instructions.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Understand and use WORKDIR and USER instructions.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Understand security-related topics.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Understand the differences and applicability of CMD vs. ENTRYPOINT instructions.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Understand ENTRYPOINT instruction with param.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Understand when and how to expose ports from a Docker file.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Understand and use environment variables inside images.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Understand ENV instruction.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Understand container volume.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Mount a host directory as a data volume.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Understand security and permissions requirements related to this approach.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Understand lifecycle and cleanup requirements of this approach.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Manage images&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt; &lt;em&gt;Understand private registry security.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Interact with many different registries.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Understand and use image tags.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Push and pull images from and to registries.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Back up an image with its layers and meta data vs. backup a container state.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Run containers locally using Podman&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt; &lt;em&gt;Get container logs.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Listen to container events on the container host.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Use Podman inspect.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Basic OpenShift knowledge&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;  &lt;em&gt;Creating applications in OpenShift&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt; &lt;em&gt;Create, manage and delete projects from a template, from source code, and from an image.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Customize catalog template parameters.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Specifying environment parameters.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Expose public applications.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Troubleshoot applications in OpenShift&lt;/em&gt;

&lt;ul&gt;
&lt;li&gt; &lt;em&gt;Understand the description of application resources.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Get application logs.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Inspect running applications.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Connecting to containers running in a pod.&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt; &lt;em&gt;Copy resources to/from containers running in a pod.&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I found the course to be really well. Getting to start locally on a workstation using podman and creating Dockerfiles (or Containerfiles, as they are called in Red Hat/podman terminology) - evolving the same application to be built highly available in an OpenShift cluster is very useful in order to understand how everything works.&lt;/p&gt;

&lt;p&gt;If you do not have access to a Red Hat Learning Subscription with access to their courses, an alternative to get hands-on experience is to set up &lt;a href="https://developers.redhat.com/products/openshift-local/getting-started"&gt;Red Hat OpenShift Local&lt;/a&gt; (formerly Red Hat CodeReady Containers) on your local computer.&lt;/p&gt;

&lt;p&gt;Another alternative is the &lt;a href="https://developers.redhat.com/developer-sandbox"&gt;OpenShift Sandbox&lt;/a&gt;, which provides 30 days of free access to an OpenShift cluster.&lt;/p&gt;

&lt;p&gt;Back to the exam, I did pass on my first attempt (a score of 269 of 300, where the minimum required is 210). However, time management is critical as usual in these hands-on exams where you get access to a virtual machine where all you have is a browser windows with the assignments as well as a terminal. Being stuck on one of the initial tasks really puts pressure on you, and while I was doubtful during the first 30 minutes - I managed to pull it off at the end.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tips and tricks
&lt;/h3&gt;

&lt;p&gt;One neat trick I learned from the DO180 course was the idea of bringing local tooling into containers during troubleshooting.&lt;br&gt;
I suppose you also have been in a situation where you are opening a terminal session against a container for diagnosing some problem, for example related to networking. Next, you find that basic tools like &lt;code&gt;ping&lt;/code&gt; and &lt;code&gt;nslookup&lt;/code&gt; is missing. On the smallest images, even tools like &lt;code&gt;ls&lt;/code&gt; may be left out in order to minimize the size of the image.&lt;/p&gt;

&lt;p&gt;The trick suggested in the course is to temporarily access some of these missing commands by mounting the host binaries folders, such as /bin, /sbin, and /lib, as volumes inside the container:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;podman run -it -v /bin:/bin image /bin/bash&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;Having seen and experienced the additional value Red Hat brings to the table on top of vanilla Kubernetes has been very interesting, such as learning about the Source-to-Image (S2I) feature.&lt;/p&gt;

&lt;p&gt;Especially for those already in the Red Hat ecosystem - it should be a no-brainer on which container platform to choose.&lt;/p&gt;

&lt;p&gt;For others, your mileage may vary as always - everyone has different needs and requirements. Regardless, I will for sure bring this alternative to the table in my container workshops.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://lzone.de/cheat-sheet/Openshift"&gt;OpenShift Command-line Tool cheat sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.mastertheboss.com/soa-cloud/openshift/openshift-cheatsheet/"&gt;Openshift Container Platform cheat sheet for System Administrators and Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=redhat.vscode-openshift-connector"&gt;Visual Studio Code Extension: OpenShift Connector&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://marketplace.visualstudio.com/items?itemName=redhat.vscode-tekton-pipelines"&gt;Visual Studio Code Extension: Tekton Pipelines (used for S2I)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=Kx110kqoHo0"&gt;Deploying a Windows Server 2019 virtual machine using OpenShift virtualization&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.openshift.com/container-platform/4.10/cicd/pipelines/understanding-openshift-pipelines.html"&gt;Understanding OpenShift Pipelines&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.openshift.com/container-platform/4.10/windows_containers/index.html"&gt;Red Hat OpenShift support for Windows Containers overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.openshift.com/container-platform/4.10/virt/logging_events_monitoring/virt-openshift-cluster-monitoring.html"&gt;OpenShift Container Platform cluster monitoring, logging, and Telemetry&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://cloud.redhat.com/blog/a-guide-to-controller-ingress-for-azure-red-hat-openshift"&gt;A Guide to Ingress Controllers for Azure Red Hat OpenShift&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devops</category>
      <category>containers</category>
      <category>redhat</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>How To Get Started with VS Code Development containers</title>
      <dc:creator>Jan Egil Ring</dc:creator>
      <pubDate>Mon, 31 Jan 2022 17:06:37 +0000</pubDate>
      <link>https://dev.to/janegilring/how-to-get-started-with-vs-code-development-containers-4alo</link>
      <guid>https://dev.to/janegilring/how-to-get-started-with-vs-code-development-containers-4alo</guid>
      <description>&lt;h3&gt;
  
  
  Introduction
&lt;/h3&gt;

&lt;p&gt;When working with code, whether it is software, Infrastructure as Code or other purposes, there are some common challenges.&lt;br&gt;
One of them is the lead time for onboarding new members to a team or a project, due to prerequisites needed for the tasks the new person will be working on.&lt;/p&gt;

&lt;p&gt;In this article, we will use the Infrastructure as Code and cloud automation as our main scenario.&lt;/p&gt;

&lt;p&gt;The specific tools needed will of course vary from project to project, but some common ones might be Terraform for declarative configurations, PowerShell for scripting and administrative tasks and VS Code as an editor. Along with these example stack of tools comes additional prerequisites, such as VS Code extensions, PowerShell modules, linting tools and so on. Lastly, there are different versions of the tools mentioned as well as the related prerequisites such as PowerShell modules and various libraries.&lt;/p&gt;

&lt;p&gt;Another aspect is that people use different platforms, such as Linux, macOS and Windows. Even when using the same operating system, there might be differences related to versions and patch levels.&lt;/p&gt;

&lt;p&gt;In the end, there is a whole lot of variations which can make it very challenging to have a consistent development environment.&lt;/p&gt;

&lt;p&gt;This is not a problem new to the world of software and infrastructure. Container technologies was born with these exact challenges as one of their main tasks to solve. Portability, being able to run the software consistently across different environments such as on-premises or different cloud vendors, is another advantage containers brings to the table.&lt;/p&gt;

&lt;p&gt;So how can containers assist with the development environment challenges discussed above? What if we could leverage containers and host each project we are working on in VS Code inside a fully isolated environment?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FzGqoi2Z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FzGqoi2Z.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Image credit: &lt;a href="https://www.docker.com/resources/what-container" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this guide, you will learn how to set up VS Code development containers - which makes this possible:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FGuWn0Ms.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FGuWn0Ms.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Image credit: &lt;a href="https://code.visualstudio.com/docs/remote/containers" rel="noopener noreferrer"&gt;Microsoft&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;When you're finished, you'll be able to leverage dev containers both for your personal projects as well as for team projects and have a consistent development environment.&lt;/p&gt;
&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;Before you begin this guide you'll need the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A computer running either Linux, macOS or Windows&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.docker.com/products/docker-desktop" rel="noopener noreferrer"&gt;Docker Desktop&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com" rel="noopener noreferrer"&gt;Visual Studio Code&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Step 1 — Install the Visual Studio Code Remote - Containers extension
&lt;/h2&gt;

&lt;p&gt;The first thing we are going to do after installing the prerequisites is to install the VS Code Remote - Containers extension.&lt;/p&gt;

&lt;p&gt;Open VS Code and navigate to the Extensions item in the sidebar. Next, search for "remote containers":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FnWNiYNh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FnWNiYNh.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click on "Remote - Containers" and click the Install button which becomes available after clicking on the button.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; &lt;em&gt;Alternatively, you may install the "Remote Development" extension pack at the bottom of the above screenshot. This contains the "Remote - Containers" extension as well as two other very useful extensions: "Remote SSH" for connecting to remote SSH targets as well as "Remote - WSL" which makes it very convenient to work with the Windows Subsystem for Linux from VS Code on Windows.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 2 — Create a new folder
&lt;/h2&gt;

&lt;p&gt;Create a new, empty folder with the purpose of creating your first dev container. Open that folder in VS Code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd ~
mkdir myfirstdevcontainer
code .\myfirstdevcontainer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FzWHDogO.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FzWHDogO.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select "Yes, I trust the authors" when the new empty folder is being opened in VS Code.&lt;/p&gt;

&lt;p&gt;We are now ready to create our first dev container.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3 — Create a dev container
&lt;/h2&gt;

&lt;p&gt;Open the &lt;a href="https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette" rel="noopener noreferrer"&gt;Command pallette&lt;/a&gt; in VS Code by using Ctrl+Shift+P (Linux/Windows) or Cmd+Shift+P (macOS) and search for Remote Containers&lt;/p&gt;

&lt;p&gt;Choose &lt;em&gt;Add Development Container Configuration Files&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;A number of templates is available. You may choose the one you want, but for this demo we will be using the Ubuntu template:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FGZcQLkp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FGZcQLkp.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we will use the focal distro for our testing purposes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FMZSmqqN.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FMZSmqqN.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finally, we may choose to install additional tools into our new container image. Here are the ones I chose:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fz2yjCnV.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fz2yjCnV.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click Ok when finished.&lt;/p&gt;

&lt;p&gt;Next, we will be prompted which version of the tools we selected we want to install. In a real world scenario, we would typically pin specific versions for consistency and stability. For this demo, I chose &lt;strong&gt;latest&lt;/strong&gt; for all prompts.&lt;/p&gt;

&lt;p&gt;At the end, we should now automatically get a subfolder called .devcontainer along with two files: devcontainer.json and Dockerfile:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fz9HhbVY.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2Fz9HhbVY.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This folder is typically stored at the root of a source control repository, hence it becomes available for all other people who have cloned the repository.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 4 - Open the newly created dev container
&lt;/h1&gt;

&lt;p&gt;When VS Code detects the two files we created in the previous step at the root of a folder, it will prompt whether we want to "Reopen in Container":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FMryErHW.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FMryErHW.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Should the "Remote - Containers" extension not be installed, you will be prompted to install it.&lt;/p&gt;

&lt;p&gt;An alternative approach to reopen the current folder inside the dev container is to once again open the Command pallette and search for Remote Containers. Next, select "Reopen in Container":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F72WNZUT.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F72WNZUT.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;VS Code will now reopen and the following status will be shown:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FhGfFjsX.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FhGfFjsX.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Under the hood, the command &lt;code&gt;docker build&lt;/code&gt; is now being run against the Dockerfile we created previously. This will result in a local container image becoming available on our machine.&lt;/p&gt;

&lt;p&gt;The build step might take from a few seconds until a few minutes depending upon the size of the base image we chose, the number of tools to install, the bandwidth of our internet connection as well as the performance of the local machine.&lt;/p&gt;

&lt;p&gt;The build step is only needed whenever a change has been made to the configuration files for the development container, so the next time you open the folder inside the dev container, it will typically open in seconds - similar to when opening a regular local folder.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 5 - Using the dev container
&lt;/h1&gt;

&lt;p&gt;When the build process has completed, you should see the folder opened in the VS Code file explorer as usual. The difference is that it is now opened within the dev container, which is indicated here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FrANmKHB.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FrANmKHB.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can click on the green "Dev Container" button to bring up a menu with relevant options such as reopening the folder locally and so on:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FMi6Ao4V.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FMi6Ao4V.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, let us explore how extensions comes into play when working with dev containers. Navigate to the Extensions item on the sidebar. You should see the following:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FlhNjWL3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FlhNjWL3.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This means we can have separate VS Code extensions per container, and we don`t have to "clutter" our local VS Code instance with numerous extensions (which may also decrease performance/load times).&lt;/p&gt;

&lt;p&gt;To install extensions inside the dev container, simply search and install them from the extensions item as usual. In this example, I will go ahead and install the PowerShell extension by clicking Install on the bottom recommandation.&lt;/p&gt;

&lt;p&gt;After installing the PowerShell extension, I will go ahead and create the file test.ps1 in the root of the myfirstdevcontainer folder. When opening the file in the editor, the PowerShell extension kicks in and opens the PowerShell Integrated Console automatically:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FcI7F4zx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FcI7F4zx.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations! You are now ready to start using PowerShell inside your newly created dev container.&lt;/p&gt;

&lt;p&gt;If you are not a PowerShell user, feel free to explore the use of the tools you use.&lt;/p&gt;

&lt;h2&gt;
  
  
  6 - Gotchas
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Operating system
&lt;/h3&gt;

&lt;p&gt;A major difference if you are Windows user, is that PowerShell is now running inside a Linux container:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FnKVTZOQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2FnKVTZOQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One option could be swapping the base image to for example the mcr.microsoft.com/powershell:lts-7.2.0-windowsserver-ltsc2022 image which can be found on &lt;a href="https://hub.docker.com/_/microsoft-powershell" rel="noopener noreferrer"&gt;Docker Hub&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Unfortunately, Windows-based images is not supported (at the time of this writing) for use in the VS Code Dev container extension.&lt;/p&gt;

&lt;p&gt;However, in this modern world of cloud infrastructure, basic Linux administration is becoming a more and more an relevant skill. Personally, I went through a learning journey in the past couple of years - ending with the &lt;strong&gt;LFCS: Linux Foundation Certified Systems Administrator&lt;/strong&gt; certification. You can read more about my journey in &lt;a href="https://www.powershell.no/linux,/powershell,/devops/2021/02/25/learning-linux.html" rel="noopener noreferrer"&gt;this article&lt;/a&gt; on my personal blog.&lt;/p&gt;

&lt;h3&gt;
  
  
  Containers are stateless
&lt;/h3&gt;

&lt;p&gt;By nature, containers are stateless. This means that all changes performed inside the container is lost when the container stops and starts. The solution to this is mounting persistent data volumes inside the container.&lt;/p&gt;

&lt;p&gt;This is something the VS Code extension handles for us automatically when it comes to the project folder we reopened from the local computer:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F4u1Gm9v.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fi.imgur.com%2F4u1Gm9v.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This means that all data inside this folder will persist, but if you place data in other folders - they will be lost.&lt;br&gt;
Also, if you install software inside the container manually - they will also be gone the next time the container image is rebuilt. If you want to install something persistently, the solution is to add the installation command to the Dockerfile and rebuild the container.&lt;/p&gt;

&lt;p&gt;In addition to mounting folders from the local machine like the VS Code extension does automatically for the project folder, it is possible to both add additional bind mounts as well as create docker volumes for persistent storage.&lt;/p&gt;

&lt;p&gt;You can read more about this in the &lt;a href="https://docs.docker.com/storage/" rel="noopener noreferrer"&gt;Docker documentation&lt;/a&gt; as well as the &lt;a href="https://code.visualstudio.com/remote/advancedcontainers/add-local-file-mount" rel="noopener noreferrer"&gt;VS Code documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  7 - Under the hood
&lt;/h2&gt;

&lt;p&gt;Let us have a deeper look at the two configuration files that the VS Code extension created for us in the previous steps.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;devcontainer.json&lt;/code&gt; contains the settings for the VS Code - Remote Containers extension:&lt;br&gt;
`&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ubuntu"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"dockerfile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Dockerfile"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Update&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'VARIANT'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pick&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;an&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Ubuntu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;version:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;hirsute&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;focal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;bionic&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;hirsute&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;or&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;bionic&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;arm&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="err"&gt;/Apple&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Silicon.&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"args"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"VARIANT"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"focal"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;*default*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;container&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;specific&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;settings.json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;values&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;on&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;container&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;create.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"settings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;


    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;IDs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;extensions&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;you&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;want&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;installed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;container&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;created.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"extensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'forwardPorts'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;make&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ports&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;inside&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;container&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;available&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;locally.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"forwardPorts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'postCreateCommand'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;commands&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;after&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;container&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;created.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"postCreateCommand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uname -a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Comment&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;out&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;connect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;instead.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;More&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;info:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://aka.ms/vscode-remote/containers/non-root.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"remoteUser"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vscode"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"features"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"kubectl-helm-minikube"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"terraform"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"github-cli"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"azure-cli"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"latest"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"powershell"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"latest"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As we can see, we can customize it further by adding extensions for example. If adding the id of the PowerShell extension (ms-vscode.PowerShell) to the "extensions" property in the json-file - it will get installed automatically when the image is built.&lt;/p&gt;

&lt;p&gt;Here is an example for the extensions I typically use in my Infrastructure as Code dev containers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    "extensions": ["ms-vscode.powershell","ms-vscode.azure-account","hashicorp.terraform","takumii.markdowntable","ms-kubernetes-tools.vscode-kubernetes-tools","ms-kubernetes-tools.vscode-aks-tools"],
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next is the &lt;code&gt;Dockerfile&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.205.2/containers/ubuntu/.devcontainer/base.Dockerfile&lt;/span&gt;

&lt;span class="c"&gt;# [Choice] Ubuntu version (use hirsuite or bionic on local arm64/Apple Silicon): hirsute, focal, bionic&lt;/span&gt;
&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; VARIANT="hirsute"&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; mcr.microsoft.com/vscode/devcontainers/base:0-${VARIANT}&lt;/span&gt;

&lt;span class="c"&gt;# [Optional] Uncomment this section to install additional OS packages.&lt;/span&gt;
&lt;span class="c"&gt;# RUN apt-get update &amp;amp;&amp;amp; export DEBIAN_FRONTEND=noninteractive \&lt;/span&gt;
&lt;span class="c"&gt;#     &amp;amp;&amp;amp; apt-get -y install --no-install-recommends &amp;lt;your-package-list-here&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you have worked with containers before, there is nothing special about this file. It is a regular Dockerfile which you can define as you want. In our example, we happened to use a predefined base-image - but we could choose to replace this with your own image. For example, you can choose to use the official PowerShell image as a base - which I actually do for a few of my own dev containers:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; mcr.microsoft.com/powershell:7.2.1-ubuntu-focal&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nt"&gt;-y&lt;/span&gt; upgrade

&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install &lt;/span&gt;azure-cli

&lt;span class="k"&gt;SHELL&lt;/span&gt;&lt;span class="s"&gt; ["pwsh", "-Command", "$ErrorActionPreference = 'Stop'; $ProgressPreference = 'SilentlyContinue';"]&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;Install-Module PSDepend &lt;span class="nt"&gt;-Force&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; ["powershell/requirements.psd1", "/tmp/requirements.psd1"]&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;Invoke-PSDepend /requirements.psd1 &lt;span class="nt"&gt;-Force&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;az aks install-cli &lt;span class="nt"&gt;--install-location&lt;/span&gt; /usr/local/bin/kubectl &lt;span class="nt"&gt;--kubelogin-install-location&lt;/span&gt; /usr/local/bin/kubelogin &lt;span class="nt"&gt;--client-version&lt;/span&gt; 1.22.0

&lt;span class="c"&gt;# Switch to non-root user:&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;useradd &lt;span class="nt"&gt;--create-home&lt;/span&gt; vscode
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /home/vscode&lt;/span&gt;
&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="s"&gt; vscode&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;Install-Module &lt;span class="nt"&gt;-Name&lt;/span&gt; oh-my-posh &lt;span class="nt"&gt;-Force&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;Install-Module &lt;span class="nt"&gt;-Name&lt;/span&gt; PSReadLine &lt;span class="nt"&gt;-Force&lt;/span&gt; &lt;span class="nt"&gt;-AllowPreRelease&lt;/span&gt;
```



As you can see, I also install the PSDepend PowerShell module in order to install a set of pre-defined PowerShell modules as defined in requirements.psd1.

Alternatively, you may install PowerShell modules the regular way using Install-Module as seen on the last two lines in the Dockerfile.

Or of course any package you need using apt-get or the relevant package manager/setup file for the software you need.

## 8 - Tips and tricks


&lt;span class="c"&gt;### 1 - Personalizing the environment with dotfile repositories&lt;/span&gt;

As stated in the [documentation](https://code.visualstudio.com/docs/remote/containers&lt;span class="c"&gt;#_personalizing-with-dotfile-repositories):&lt;/span&gt;

&amp;gt;Dotfiles are files whose filename begins with a dot (.) and typically contain configuration information for various applications. Since development containers can cover a wide range of application types, it can be useful to store these files somewhere so that you can easily copy them into a container once it is up and running.

&amp;gt;A common way to do this is to store these dotfiles in a GitHub repository and then use a utility to clone and apply them. The Remote - Containers extension has built-in support for using these with your own containers. If you are new to the idea, take a look at the different dotfiles bootstrap repositories that exist.

For PowerShell users, a tip for having a synchronized PowerShell profile across machines and containers is using a GitHub Gist like PowerShell team member Steve Lee describes is the article [Optimizing your $Profile](https://devblogs.microsoft.com/powershell/optimizing-your-profile/).
For anyone interested, my profile is available in [this](https://gist.github.com/janegilring/a4e366e6b01f0b70eae90557dfc9d21d) Gist.

### 2 - CPU architectures

I recently got a Mac with the new [Apple silicon](https://support.apple.com/en-us/HT211814) based CPU - also referred to as [arm64 or ARMv8](https://en.wikipedia.org/wiki/ARM_architecture&lt;span class="c"&gt;#ARMv8).&lt;/span&gt;

After trying to leverage amd64-based images defined in my existing dev-container files, it sort of worked. However, the performance was very poor and very noticeable when working interactively via the command line. I also experienced some occasianal errors regarding segmentation faults when building the Docker image for my dev-container. It mostly does work due to an emulation layer, but performance is expected to be significantly slower.
As this was not going to work in practice, I looked into changing the following into arm64-based versions:
- [Docker image](mcr.microsoft.com/dotnet/runtime:6.0.1-focal-arm64v8)
- [PowerShell](https://github.com/PowerShell/PowerShell/releases/download/v7.2.1/powershell-7.2.1-linux-arm64.tar.gz)
- [oh-my-posh](https://github.com/JanDeDobbeleer/oh-my-posh/releases/download/v7.5.1/posh-linux-arm64)
- [Azure CLI](https://packages.microsoft.com/repos/azure-cli/dists/focal/Contents-arm64.gz)
- [Terraform](https://releases.hashicorp.com/terraform/1.1.4/terraform_1.1.4_darwin_arm64.zip)

After rebuilding and testing the updated dev-container, performance was outstanding for interactive use. I have not conducted any performance tests, but at least the responsiveness and speed in interactive use was the fastest I have worked with.

Fundamentally, amd64 cores are similar but arm64 have different cores for different tasks. arm64 is typically more efficient, both with regards to performance and energy use. However, due to the underlying differences, software must be compiled against the new architecture in order to run natively.

All of the tooling I needed was available in arm64 editions, but not all software is. Hence, it is recommended to check arm64 availability for the software you are working with before trying to use it on the new Apple silicon.

Another important aspect is team projects. It is becoming more and more common to have devcontainer-files in source control which everyone on a team or project can leverage for consistent development environments. Be aware of the CPU architecture challenge in this situation, in case team members are working on different hardware. One possible workaround to this challenge is to leverage a [remote host](https://leimao.github.io/blog/VS-Code-Development-Remote-Host-Docker/) or [GitHub Codespaces](https://docs.github.com/en/codespaces) for common projects if your team is working with amd64-based hardware and you are on arm64, for example.

### 3 - Sharing Git credentials with your container

Also from the [documentation](https://code.visualstudio.com/docs/remote/containers&lt;span class="c"&gt;#_sharing-git-credentials-with-your-container):&lt;/span&gt;

&amp;gt;The Remote - Containers extension provides out of box support for using local Git credentials from inside a container.

In the documentation, they will walk through the two supported options.

I would encourage you to read through the [documentation](https://code.visualstudio.com/docs/remote/containers&lt;span class="c"&gt;#_getting-started) for the *VS Code - Remote containers* extension for additional information and configuration options you might want to customize.&lt;/span&gt;

&lt;span class="c"&gt;## Conclusion&lt;/span&gt;

In this article you learned how to get started with VS Code Development containers.

The extension makes it very convenient to perform development work inside a running container based on a standardized setup which can be shared across teams using regular source control.
Installing software on a local machine will over time lead to a cluttered environment with many different versions of SDKs, libraries and other software. Many of these software installations will change environment settings such as the Path variable, which can lead to unpredictable results in many situations. Dev containers solves the classical "it works on my machine" issue. Even though you do not need to containerize your applications in order to use VS Code dev containers, it will make it even more convenient to troubleshoot production issues when you can start a local instance of the container and access is from a dev container. Some software also have issues running different versions side-by-side, making it necessary to either have multiple dev machines or install/uninstall different versions. Dev containers helps solve this issue, as one can simply rebuild a dev container using a different version or have different dev containers for different environments (test/QA/production for example).

Now you can start using them both for your personal projects as well as team projects in order to benefit from consistent development environments.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>vscode</category>
      <category>docker</category>
      <category>containers</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
