<?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: Sebastián Gómez</title>
    <description>The latest articles on DEV Community by Sebastián Gómez (@sebagomez).</description>
    <link>https://dev.to/sebagomez</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%2F61999%2F828e6fbf-2ea8-4694-8491-6e8cfc2ba567.JPG</url>
      <title>DEV Community: Sebastián Gómez</title>
      <link>https://dev.to/sebagomez</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sebagomez"/>
    <language>en</language>
    <item>
      <title>GeneXus application running on Kubernetes</title>
      <dc:creator>Sebastián Gómez</dc:creator>
      <pubDate>Mon, 02 Mar 2020 22:32:13 +0000</pubDate>
      <link>https://dev.to/sebagomez/genexus-application-running-on-kubernetes-4go1</link>
      <guid>https://dev.to/sebagomez/genexus-application-running-on-kubernetes-4go1</guid>
      <description>&lt;p&gt;Some time ago I started playing with Docker. I felt in love with it, I've written some posts about it and I think every developer should take a look at Docker for both production and development environments.&lt;/p&gt;

&lt;p&gt;After learning about Docker containers, the next thing you hear is Kubernetes. I didn't know why I would need it, but then I understood what's so great about it. &lt;/p&gt;

&lt;p&gt;I believe its portability is its killer feature. If you're not familiar with Kubernetes, this is not the best post, to begin with. There are tons of tutorials and great docs online.&lt;/p&gt;

&lt;p&gt;This is my story on how I managed to deploy a GeneXus web app with Kubernetes.&lt;/p&gt;

&lt;p&gt;This is what I wanted to achieve:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3wjfyacm45pkudk2gsnf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F3wjfyacm45pkudk2gsnf.png" alt="My Architecture" width="800" height="444"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My application needs access to a relational database. It works pretty well with MySQL so I'm planning to work on some MySQL-As-A-Service (in this case I'm using &lt;a href="https://cloud.ibm.com/catalog/services/compose-for-mysql" rel="noopener noreferrer"&gt;IBM's Compose for MySQL&lt;/a&gt;).&lt;br&gt;
It does have some heavy processing, so in some cases, I might need to scale up (horizontally) to up to 3 nodes, or hopefully more. But that brings some challenges... I don't want to rely on the file system of the nodes, so I set a Storage Account (this time with &lt;a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-introduction" rel="noopener noreferrer"&gt;Azure Storage&lt;/a&gt;) and I want to use that as the File System of my application.&lt;br&gt;&lt;br&gt;
The other problem I might hit has to do with the web sessions. My application makes heavy use of web sessions, and in a distributed environment I don't want to rely on server affinity.&lt;br&gt;&lt;br&gt;
So I thought about using Redis for caching and session managing. Setting up Redis for caching in GeneXus is easy, just turn on a property and that's it. For session manager is a little bit more complicated, but it is not hard, you will see it in a minute.&lt;/p&gt;

&lt;p&gt;Also, since I'm using Docker containers, I don't need to know how to install Redis, I'll just &lt;a href="https://hub.docker.com/_/redis" rel="noopener noreferrer"&gt;pull an image from Docker Hub&lt;/a&gt; and that's it (in this case I'm using redis:5.0.7-alpine).&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 0
&lt;/h3&gt;

&lt;p&gt;Compile and run my application locally. Everything is fine? cool, keep going!&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 1
&lt;/h3&gt;

&lt;p&gt;Deploy the application to Docker. But here's where we need to change a few things outside of GeneXus.&lt;br&gt;
For the (in this case java) application to use Redis as a Cache and Session manager, we need to modify a few things from the base image we will use, so this is the dockerfile I created to build my image.&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;# Dockerfile generated by GeneXus (Java)&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; tomcat:9-jdk11&lt;/span&gt;
&lt;span class="k"&gt;LABEL&lt;/span&gt;&lt;span class="s"&gt; maintainer="seba &amp;lt;seba@example.com&amp;gt;"&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /usr/local/tomcat/webapps/&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; ROOT/ &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;mv &lt;/span&gt;ROOT/ ROOT.old/ &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="s"&gt; ["ROOT.war", "/usr/local/tomcat/webapps/"]&lt;/span&gt;

&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="s"&gt; redis/*.jar /usr/local/tomcat/lib/&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="s"&gt; redis/*.xml /usr/local/tomcat/conf/&lt;/span&gt;
&lt;span class="k"&gt;ADD&lt;/span&gt;&lt;span class="s"&gt; redis/redis-data-cache.properties /usr/local/tomcat/conf&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The dockerfile is a standard (GeneXus generated) dockerfile until the first blank line. The last three commands are the ones I added myself. Those files added to the image are used by the &lt;a href="https://github.com/ran-jit/tomcat-cluster-redis-session-manager" rel="noopener noreferrer"&gt;Tomcat Clustering Redis Session Manager&lt;/a&gt; I've used.&lt;/p&gt;

&lt;p&gt;After modifying the dockerfile I ran the following commands:&lt;br&gt;
&lt;code&gt;docker build -t k8stestjavaenvironment .&lt;/code&gt; to build the image&lt;br&gt;
&lt;code&gt;docker tag k8stestjavaenvironment sebagomez/genexus-wwhero&lt;/code&gt; to tag the image to something that I can push to a registry, and...&lt;br&gt;
&lt;code&gt;docker push sebagomez/genexus-wwhero&lt;/code&gt; to push it  &lt;/p&gt;

&lt;p&gt;Now there's a Docker &lt;a href="https://hub.docker.com/r/sebagomez/genexus-wwhero" rel="noopener noreferrer"&gt;image in Docker's public registry&lt;/a&gt; with my application (and everything needed to run).&lt;/p&gt;
&lt;h3&gt;
  
  
  Step 2
&lt;/h3&gt;

&lt;p&gt;Create the Kubernetes yaml file. I'm not trying to teach Kubernetes here but this is the file, and I'll tell you what the different sections are&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gx-java-app&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gx-java-app&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gx-java-app&lt;/span&gt;
    &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;NodePort&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt; &lt;span class="c1"&gt;# for versions before 1.9.0 use apps/v1beta2&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gx-java-app&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gx-java-app&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gx-java-app&lt;/span&gt;
      &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Recreate&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gx-java-app&lt;/span&gt;
        &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;frontend&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;sebagomez/genexus-wwhero&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;k8stest-genexus-java-app&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GX_COM_K8STEST_DEFAULT_USER_ID&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;MySQL User&amp;gt;&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GX_COM_K8STEST_DEFAULT_USER_PASSWORD&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;MySQL Password&amp;gt;&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;GX_COM_K8STEST_DEFAULT_DB_URL&lt;/span&gt;
          &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;jdbc:mysql://&amp;lt;MySQL Service&amp;gt;/K8sTest?useSSL=false&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gx-java-app&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gx-redis&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;genexus-java-app&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6379&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;genexus-java-app&lt;/span&gt;
    &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
  &lt;span class="na"&gt;clusterIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;None&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt; &lt;span class="c1"&gt;# for versions before 1.9.0 use apps/v1beta2&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;gx-redis&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;genexus-java-app&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;genexus-java-app&lt;/span&gt;
      &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
  &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Recreate&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;genexus-java-app&lt;/span&gt;
        &lt;span class="na"&gt;tier&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis:5.0.7-alpine&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;6379&lt;/span&gt;
          &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;redis&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first section is the service for the web app. When you deploy an app via Kubernetes it does not get exposed by default, you need to create a &lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/" rel="noopener noreferrer"&gt;Kubernetes Service&lt;/a&gt; and that's what that first section is.&lt;br&gt;
The second section is the &lt;a href="https://kubernetes.io/docs/concepts/workloads/controllers/deployment/" rel="noopener noreferrer"&gt;deployment&lt;/a&gt; of my web application itself. Notice I'm using the image tagged before and I'm using environment variables inside the cluster for configuration.&lt;br&gt;
Then I'm setting up another service for the Redis deployment. This service does not get exposed outside of the cluster, it'll be only used by my application.&lt;br&gt;
And lastly, the redis container itself.&lt;/p&gt;

&lt;p&gt;It sounds like a lot but it is quite easy, and easy to automate. Soon GeneXus will be able to generate that yaml based on your needs.&lt;/p&gt;

&lt;p&gt;That allowed me to have my very own cluster on my machine. &lt;code&gt;kubectl apply -f .\myapp.yaml&lt;/code&gt; and the clusters starts.&lt;/p&gt;

&lt;p&gt;But the great thing is, and this is what's great about Kubernetes (IMHO), I can take that exact yaml file to IBM's cloud and start a new cluster with my app. And I'm doing the same with Azure and AWS, so I built a Cloud Native application which is Cloud Provider agnostic, and I can take it wherever I want to.&lt;/p&gt;

&lt;p&gt;Isn't that cool?!&lt;/p&gt;

&lt;p&gt;Let me know your thoughts&lt;br&gt;
Happy deploying!&lt;/p&gt;

</description>
      <category>genexus</category>
      <category>kubernetes</category>
      <category>redis</category>
      <category>mysql</category>
    </item>
    <item>
      <title>Windows Containers (personal) cheat sheet</title>
      <dc:creator>Sebastián Gómez</dc:creator>
      <pubDate>Wed, 20 Feb 2019 17:08:09 +0000</pubDate>
      <link>https://dev.to/sebagomez/windows-containers-personal-cheat-sheet-o1</link>
      <guid>https://dev.to/sebagomez/windows-containers-personal-cheat-sheet-o1</guid>
      <description>&lt;p&gt;I’ve been struggling to get a web app (ASP.NET 4) with some ReST services in a Windows Container. It was actually three different apps, two of them are web applications and the other is just a big batch process which must be called via MSBuild.&lt;/p&gt;

&lt;p&gt;More than a cheat sheet, this is just a note for my future self… and maybe it’ll help someone along the way.&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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fq0yncee7ynpl2sdxtd3l.jpg" 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%2Fthepracticaldev.s3.amazonaws.com%2Fi%2Fq0yncee7ynpl2sdxtd3l.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
Image source https://blog.newrelic.com/culture/dockercon-sf/



&lt;p&gt;Here’s my dockerfile, I’ll go thru each line below 👇&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here we go:&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;# escape=`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The escape char is used to span multiple lines. The default char is the backslash &lt;code&gt;\&lt;/code&gt; but since that’s also Windows directory separator it would get messy. That line can only be at the beginning, and the backtick &lt;code&gt;`&lt;/code&gt;is the only possible value (other than the default). Read more about the &lt;a href="https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-docker/manage-windows-dockerfile#escape-character" rel="noopener noreferrer"&gt;escape char&lt;/a&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="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; microsoft/dotnet-framework:4.7.2-runtime&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I’ll start from that image since it’s the needed runtime for my applications.&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;LABEL&lt;/span&gt;&lt;span class="s"&gt; MAINTAINER="Seba Gómez &amp;lt;sgomez@genexus.com&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Just me&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;# GeneXus&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; GeneXus/ c:/GeneXus&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;C:/GeneXus/Genexus.com /install &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;
    powershell -Command "Copy-Item C:/Users/ContainerAdministrator/AppData/Roaming/GeneXus C:/Windows/SysWOW64/config/systemprofile/AppData/Roaming -Recurse"

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; Artech.* c:/GeneXus/&lt;/span&gt;

&lt;span class="c"&gt;# GeneXus M Service&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; GXM_Services/ C:/GXM_Services&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; LocalSettings.json C:/GXM_Services/GXM_Services/Services/Settings.json&lt;/span&gt;

&lt;span class="c"&gt;# GeneXus Server&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; GeneXusServer/ C:/GeneXusServer&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This is just the copy from my host into the container. Those are the different applications that will be eventually running there. I do want to take a minute on this line:&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;RUN &lt;/span&gt;powershell &lt;span class="nt"&gt;-Command&lt;/span&gt; &lt;span class="s2"&gt;"Copy-Item C:/Users/ContainerAdministrator/AppData/Roaming/GeneXus C:/Windows/SysWOW64/config/systemprofile/AppData/Roaming -Recurse"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;It doesn’t matter what I’m copying there but let me tell why I’m doing that. There’s a command I ran before that copies some files into the &lt;strong&gt;%AppData%&lt;/strong&gt; directory. But the &lt;strong&gt;%AppData%&lt;/strong&gt; directory is related to the current user… so I ran that at build time (docker build) and one of my applications tried to look for those at execution time and could not find them. Why? Because whoever copied the files is not the same user that is looking for those files. I have to copy them (manually) the where the running application will be looking for them, and that is the LocalSystem account &lt;strong&gt;%AppData%&lt;/strong&gt; folder. (&lt;a href="https://serverfault.com/questions/9325/where-can-i-find-data-stored-by-a-windows-service-running-as-local-system-accou" rel="noopener noreferrer"&gt;Stack Overlow FTW!&lt;/a&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;#ENABLE IIS&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;powershell &lt;span class="nt"&gt;-Command&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;
    Add-WindowsFeature Web-Server; `
    Add-WindowsFeature NET-Framework-45-ASPNET; `
    Add-WindowsFeature Web-Asp-Net45; `
    Add-WindowsFeature NET-WCF-TCP-Activation45; `
    Add-WindowsFeature NET-WCF-HTTP-Activation45; `
    Add-WindowsFeature Web-WebSockets; `
    New-WebAppPool GeneXusServerAppPool; `
    New-WebApplication -Name GeneXusServer -Site 'Default Web Site' -PhysicalPath C:\GeneXusServer\VDir -ApplicationPool GeneXusServerAppPool;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I then need to enable the IIS, I could have used one of those asp.net images… honestly?, I remember trying tons of stuff and this is the one that finally worked for me. So, I enable the Web-Server, and all those features you see there. I need all of them, maybe you don’t. This RUN command follows the best practices of keeping a bunch or RUN instructions in one single line. This is where we see the escape character, see it at the end of (almost) every line?&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;# Change AppPool properties&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;c:&lt;span class="se"&gt;\w&lt;/span&gt;indows&lt;span class="se"&gt;\s&lt;/span&gt;ystem32&lt;span class="se"&gt;\i&lt;/span&gt;netsrv&lt;span class="se"&gt;\a&lt;/span&gt;ppcmd.exe &lt;span class="nb"&gt;set &lt;/span&gt;app /app.name:&lt;span class="s2"&gt;"Default Web Site/"&lt;/span&gt; /enabledProtocols:&lt;span class="s2"&gt;"http,net.tcp"&lt;/span&gt; &amp;amp; &lt;span class="sb"&gt;`&lt;/span&gt;
    c:\windows\system32\inetsrv\appcmd set apppool /apppool.name:GeneXusServerAppPool /enable32BitAppOnWin64:true &amp;amp; `
    c:\windows\system32\inetsrv\appcmd set apppool /apppool.name:GeneXusServerAppPool /processModel.identityType:"LocalSystem" &amp;amp; `
    c:\windows\system32\inetsrv\appcmd set apppool /apppool.name:GeneXusServerAppPool /managedRuntimeVersion:"v4.0"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I also discovered an IIS tool called &lt;a href="https://docs.microsoft.com/en-us/iis/get-started/getting-started-with-iis/getting-started-with-appcmdexe" rel="noopener noreferrer"&gt;AppCMD&lt;/a&gt;. There’s probably a better (PowerShell?) way of doing what I needed but I couldn’t find it. So after long hours, I figured out how to change everything I needed. Again, this is dead simple with the IIS tools, enable protocols, change the identity and set the runtime of the application pool is just a click away with GUI, not with just a command line.&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;# Enable https&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; tools/enable_https.ps1 C:/tools/&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;powershell &lt;span class="nt"&gt;-File&lt;/span&gt; .&lt;span class="se"&gt;\t&lt;/span&gt;ools&lt;span class="se"&gt;\e&lt;/span&gt;nable_https.ps1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This one is kind of embarrassing, cause I didn’t know how to do it in one or many lines in the dockerfile. So I found a little PowerShell script online and used that one to create a certificate and install it in my IIS for https support.&lt;/p&gt;

&lt;p&gt;This is all the script does 👇&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;I would like to know how to do this straight in the dockerfile, if you know how to do it, please let me know.&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;#Install Chocolatey&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;powershell &lt;span class="nt"&gt;-Command&lt;/span&gt; Set-ExecutionPolicy Bypass &lt;span class="nt"&gt;-Scope&lt;/span&gt; Process &lt;span class="nt"&gt;-Force&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; iex &lt;span class="o"&gt;((&lt;/span&gt;New-Object System.Net.WebClient&lt;span class="o"&gt;)&lt;/span&gt;.DownloadString&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'https://chocolatey.org/install.ps1'&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install &lt;a href="https://chocolatey.org/" rel="noopener noreferrer"&gt;Chocolatey&lt;/a&gt;, I can't recommend using chocolatey enough. Chocolatey is the package manager for Windows, is like Ubuntu’s apt-get or whatever you use on your Mac. It’s awesome, you need to start using it in your daily basis, and it’s a must when working with Windows Containers (you’ll see why next).&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;# Install Microsoft Visual C++ Redistributable for Visual Studio 2017, URLRewrite Module and SQL Server CMD Utilities (BCP)&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;choco &lt;span class="nb"&gt;install &lt;/span&gt;vcredist140 &lt;span class="nt"&gt;-y&lt;/span&gt; &amp;amp; &lt;span class="sb"&gt;`&lt;/span&gt;
    choco install urlrewrite -y &amp;amp; `
    choco install sqlserver-cmdlineutils -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I need to install VC++ redistributable package, the URL rewrite module for IIS and the SQL Server command-line utilities because I need the &lt;a href="https://docs.microsoft.com/en-us/sql/tools/bcp-utility?view=sql-server-2017" rel="noopener noreferrer"&gt;bcp utility&lt;/a&gt; . All that is magically done by chocolatey. Seriously, go check chocolatey out.&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;# Install the Java SDK and Tomcat 8&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;choco &lt;span class="nb"&gt;install &lt;/span&gt;jdk8 &lt;span class="nt"&gt;-y&lt;/span&gt; &amp;amp; &lt;span class="sb"&gt;`&lt;/span&gt;
    choco install tomcat -y  -params "unzipLocation=C:\\Tomcat8"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I’ll also be running some Java web applications in that container, so I need to install the Java JDK and Tomcat 8.5&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;# Set the needed Tomcat registry values&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;powershell &lt;span class="nt"&gt;-Command&lt;/span&gt; &lt;span class="sb"&gt;`&lt;/span&gt;
    New-Item -Path 'HKLM:\SOFTWARE' -Name 'Apache Software Foundation'; `
    New-Item -Path 'HKLM:\SOFTWARE\Apache Software Foundation' -Name 'Tomcat'; `
    New-Item -Path 'HKLM:\SOFTWARE\Apache Software Foundation\Tomcat' -Name '8.5'; `
    New-Item -Path 'HKLM:\SOFTWARE\Apache Software Foundation\Tomcat\8.5' -Name 'Tomcat8'; `
    Set-ItemProperty -Path 'HKLM:\SOFTWARE\Apache Software Foundation\Tomcat\8.5\Tomcat8' -Name 'InstallPath' -Value 'c:\Tomcat8\apache-tomcat-8.5.12'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also, my application tries to read the registry to know where the Tomcat is installed, unfortunately (for me) installing Tomcat via chocolatey is just like unzipping the files and does not write anything in the registry. So I had to write the needed entries myself. That’s another time when PowerShell came in handy.&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;# Install Tomcat as Windows Service (and set its StartType to Automatic)&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;C:/Tomcat8/apache-tomcat-8.5.12/bin/service.bat &lt;span class="nb"&gt;install&lt;/span&gt; &amp;amp; &lt;span class="sb"&gt;`&lt;/span&gt;
    powershell Set-Service -Name Tomcat8 -StartupType Automatic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that I realized that Tomcat was not starting as a service, so I had to install it and update its StartType as Automatic so it would start right away with my container.&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;# Install the Microsoft .NET Core SDK and Windows Server Hosting&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;choco &lt;span class="nb"&gt;install &lt;/span&gt;dotnetcore-sdk &lt;span class="nt"&gt;-y&lt;/span&gt; &amp;amp; &lt;span class="sb"&gt;`&lt;/span&gt;
    choco install dotnetcore-windowshosting -y

&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; DOTNET_CLI_TELEMETRY_OPTOUT 1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I also need to run .NET Core applications, so I need to install the .NET Core SDK, because I’ll be building a project, and the Windows Server Hosting because the application will run on IIS. The last line sets the &lt;code&gt;DOTNET_CLI_TELEMETRY_OPTOUT&lt;/code&gt; environment variable to 1 so I don’t see an ugly output, but it has not worked, I still see it and don’t know why.&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;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 80 80/udp 8001 8001/udp 8080&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["powershell", "Get-Content", "C:\\GXM_Services\\GXM_Services\\GXMBLServices.log", "-Wait", "-Tail 1"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, I need to expose the needed ports and set the ENTRYPOINT. The ENTRYPOINT is also something I fixed with PowerShell. The container had nothing exposed to the standard output, so when you started the container or tried to see the logs via docker logs nothing was there. So again, PowerShell came very handy with the command &lt;a href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-content?view=powershell-6" rel="noopener noreferrer"&gt;Get-Content&lt;/a&gt;. So what I’m doing there is printing out the last line of a log file and wait for newer lines to show up.&lt;/p&gt;

&lt;p&gt;Looks simple now but it took me a while to configure everything I needed, especially the changes to the Application Pool.&lt;/p&gt;

&lt;p&gt;Someday this will all be .NET Core, but right now it’s plain .NET Framework 4.7, thus, the need for a Windows Container.&lt;/p&gt;

&lt;p&gt;When doing this I faced many tasks that are very easy to solve using Windows GUI, but that’s something that’s just not there in containers. So you’ll have to use simple CMD or PowerShell commands. I’m not a PowerShell wiz, I had to learn a lot of stuff but it’s totally worth it, if you’re not familiar with PowerShell yet, you should definitely get a big cup of coffee (or mate) and start playing with it.&lt;/p&gt;

&lt;p&gt;Know how to improve this Dockerfile? please let me know in the comments and I’ll update it accordingly.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>windowscontainers</category>
    </item>
    <item>
      <title>Windows Containers (personal) cheat sheet</title>
      <dc:creator>Sebastián Gómez</dc:creator>
      <pubDate>Fri, 08 Feb 2019 19:44:53 +0000</pubDate>
      <link>https://dev.to/sebagomez/windows-containers-personal-cheat-sheet-5fk1</link>
      <guid>https://dev.to/sebagomez/windows-containers-personal-cheat-sheet-5fk1</guid>
      <description>&lt;p&gt;I’ve been struggling to get a web app (ASP.NET 4) with some ReST services in a Windows Container. It was actually three different apps, two of them are web applications and the other is just a big batch process which must be called via MSBuild.&lt;/p&gt;

&lt;p&gt;More than a cheat sheet, this is just a note for my future self… and maybe it’ll help someone along the way.&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%2Fcdn-images-1.medium.com%2Fmax%2F700%2F1%2AbeCotwn_ZPXuBw4FvSGGRA.jpeg" 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%2Fcdn-images-1.medium.com%2Fmax%2F700%2F1%2AbeCotwn_ZPXuBw4FvSGGRA.jpeg"&gt;&lt;/a&gt;image source: &lt;a href="https://blog.newrelic.com/culture/dockercon-sf/" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://blog.newrelic.com/culture/dockercon-sf/" rel="noopener noreferrer"&gt;https://blog.newrelic.com/culture/dockercon-sf/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s my dockerfile, I’ll go thru each line below 👇&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here we go:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# escape=`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;The escape char is used to span multiple lines. The default char is the backslash \ but since that’s also Windows directory separator it would get messy. That line can only be at the beginning, and the backtick `is the only possible value (other than the default). Read more about the &lt;a href="https://docs.microsoft.com/en-us/virtualization/windowscontainers/manage-docker/manage-windows-dockerfile#escape-character" rel="noopener noreferrer"&gt;escape char&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM microsoft/dotnet-framework:4.7.2-runtime
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;I’ll start from that image since it’s the needed runtime for my applications.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LABEL MAINTAINER="Seba Gómez &amp;lt;sgomez@genexus.com&amp;gt;"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Just me&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# GeneXus
COPY GeneXus/ c:/GeneXus
RUN C:/GeneXus/Genexus.com /install &amp;amp;&amp;amp; `
    powershell -Command "Copy-Item 
    C:/Users/ContainerAdministrator/AppData/Roaming/GeneXus 
    C:/Windows/SysWOW64/config/systemprofile/AppData/Roaming -Recurse"

COPY Artech.\* c:/GeneXus/

# GeneXus M Service
COPY GXM\_Services/ C:/GXM\_Services
COPY LocalSettings.json C:/GXM\_Services/GXM\_Services/Services/Settings.json

# GeneXus Server
COPY GeneXusServer/ C:/GeneXusServer
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This is just the copy from my host into the container. Those are the different applications that will be eventually running there. I do want to take a minute on this line:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;RUN powershell -Command "Copy-Item C:/U sers/ContainerAdministrator/AppData/Roaming/GeneXus C:/Windows/SysWOW64/config/systemprofile/AppData/Roaming -Recurse"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;It doesn’t matter what I’m copying there but let me tell why I’m doing that. There’s a command I ran before that copies some files into the &lt;strong&gt;%AppData%&lt;/strong&gt; directory. But the &lt;strong&gt;%AppData%&lt;/strong&gt; directory is related to the current user… so I ran that at build time (docker build) and one of my applications tried to look for those at execution time and could not find them. Why? Because whoever copied the files is not the same user that is looking for those files. I have to copy them (manually) the where the running application will be looking for them, and that is the LocalSystem account &lt;strong&gt;%AppData%&lt;/strong&gt; folder. (&lt;a href="https://serverfault.com/questions/9325/where-can-i-find-data-stored-by-a-windows-service-running-as-local-system-accou" rel="noopener noreferrer"&gt;Stack Overlow FTW!&lt;/a&gt;)&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#ENABLE IIS
RUN powershell -Command `
    Add-WindowsFeature Web-Server; `
    Add-WindowsFeature NET-Framework-45-ASPNET; `
    Add-WindowsFeature Web-Asp-Net45; `
    Add-WindowsFeature NET-WCF-TCP-Activation45; `
    Add-WindowsFeature NET-WCF-HTTP-Activation45; `
    Add-WindowsFeature Web-WebSockets; `
    New-WebAppPool GeneXusServerAppPool; `
    New-WebApplication -Name GeneXusServer -Site 'Default Web Site' -PhysicalPath C:\GeneXusServer\VDir -ApplicationPool GeneXusServerAppPool;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;I then need to enable the IIS, I could have used one of those asp.net images… honestly?, I remember trying tons of stuff and this is the one that finally worked for me. So, I enable the Web-Server, and all those features you see there. I need all of them, maybe you don’t. This RUN command follows the &lt;a href="https://docs.docker.com/develop/develop-images/dockerfile_best-practices/" rel="noopener noreferrer"&gt;best practices&lt;/a&gt; of keeping a bunch or RUN instructions in one single line. This is where we see the escape character, see it at the end of (almost) every line?&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Change AppPool properties
RUN c:\windows\system32\inetsrv\appcmd.exe set app /app.name:"Default Web Site/" /enabledProtocols:"http,net.tcp" &amp;amp; `
c:\windows\system32\inetsrv\appcmd set apppool /apppool.name:GeneXusServerAppPool /enable32BitAppOnWin64:true &amp;amp; `
c:\windows\system32\inetsrv\appcmd set apppool /apppool.name:GeneXusServerAppPool /processModel.identityType:"LocalSystem" &amp;amp; `
c:\windows\system32\inetsrv\appcmd set apppool /apppool.name:GeneXusServerAppPool /managedRuntimeVersion:"v4.0"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;I also discovered an IIS tool called &lt;a href="https://docs.microsoft.com/en-us/iis/get-started/getting-started-with-iis/getting-started-with-appcmdexe" rel="noopener noreferrer"&gt;AppCMD&lt;/a&gt;. There’s probably a better (PowerShell?) way of doing what I needed but I couldn’t find it. So after long hours, I figured out how to change everything I needed. Again, this is dead simple with the IIS tools, enable protocols, change the identity and set the runtime of the application pool is just a click away with GUI, not with just a command line.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Enable https
COPY tools/enable\_https.ps1 C:/tools/
RUN powershell -File .\tools\enable\_https.ps1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;This one is kind of embarrassing, cause I didn’t know how to do it in one or many lines in the dockerfile. So I found a little PowerShell script online and used that one to create a certificate and install it in my IIS for https support.&lt;/p&gt;

&lt;p&gt;This is all the script does 👇&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;I would like to know how to do this straight in the dockerfile, if you know how to do it, please let me know.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#Install Chocolatey
RUN powershell -Command Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Install &lt;a href="https://chocolatey.org" rel="noopener noreferrer"&gt;Chocolatey&lt;/a&gt;. Chocolatey is the package manager for Windows, is like Windows’s apt-get or whatever you use on your Mac. It’s awesome, you need to start using it in your daily basis, and it’s a must when working with Windows Containers (you’ll see why next).&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Install Microsoft Visual C++ Redistributable for Visual Studio 2017, URLRewrite Module and SQL Server CMD Utilities (BCP)
RUN choco install vcredist140 -y &amp;amp; `
    choco install urlrewrite -y &amp;amp; `
    choco install sqlserver-cmdlineutils -y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I need to install VC++ redistributable package, the URL rewrite module for IIS and the SQL Server command-line utilities because I need the &lt;a href="https://docs.microsoft.com/en-us/sql/tools/bcp-utility?view=sql-server-2017" rel="noopener noreferrer"&gt;bcp utility&lt;/a&gt;. All that is magically done by chocolatey. Seriously, go check chocolatey out.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Install the Java SDK and Tomcat 8
RUN choco install jdk8 -y &amp;amp; `
    choco install tomcat -y -params "unzipLocation=C:\\Tomcat8"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I’ll also be running some Java web applications in that container, so I need to install the Java JDK and Tomcat 8.5&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Set the needed Tomcat registry values
RUN powershell -Command `
    New-Item -Path 'HKLM:\SOFTWARE' -Name 'Apache Software Foundation'; `
    New-Item -Path 'HKLM:\SOFTWARE\Apache Software Foundation' -Name 'Tomcat'; `
    New-Item -Path 'HKLM:\SOFTWARE\Apache Software Foundation\Tomcat' -Name '8.5'; `
    New-Item -Path 'HKLM:\SOFTWARE\Apache Software Foundation\Tomcat\8.5' -Name 'Tomcat8'; `
    Set-ItemProperty -Path 'HKLM:\SOFTWARE\Apache Software Foundation\Tomcat\8.5\Tomcat8' -Name 'InstallPath' -Value 'c:\Tomcat8\apache-tomcat-8.5.12'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Also, my application tries to read the registry to know where the Tomcat is installed, unfortunately (for me) installing Tomcat via chocolatey is just like unzipping the files and does not write anything in the registry. So I had to write the needed entries myself. That’s another time when PowerShell came in handy.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Install Tomcat as Windows Service (and set its StartType to Automatic)
RUN C:/Tomcat8/apache-tomcat-8.5.12/bin/service.bat install &amp;amp; `
powershell Set-Service -Name Tomcat8 -StartupType Automatic
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After that I realized that Tomcat was not starting as a service, so I had to install it and update its StartType as Automatic so it would start right away with my container.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Install the Microsoft .NET Core SDK and Windows Server Hosting
RUN choco install dotnetcore-sdk -y &amp;amp; `
    choco install dotnetcore-windowshosting -y

ENV DOTNET\_CLI\_TELEMETRY\_OPTOUT 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I also need to run .NET Core applications, so I need to install the .NET Core SDK, because I’ll be building a project, and the Windows Server Hosting because the application will run on IIS. The last line sets the DOTNET_CLI_TELEMETRY_OPTOUT environment variable to 1 so I don’t see an ugly output, but it has not worked, I still see it and don’t know why.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EXPOSE 80 80/udp 8001 8001/udp 8080

ENTRYPOINT ["powershell", "Get-Content", "C:\\GXM\_Services\\GXM\_Services\\GXMBLServices.log", "-Wait", "-Tail 1"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Finally, I need to expose the needed ports and set the ENTRYPOINT. The ENTRYPOINT is also something I fixed with PowerShell. The container had nothing exposed to the standard output, so when you started the container or tried to see the logs via docker logs nothing was there. So again, PowerShell came very handy with the command &lt;a href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-content?view=powershell-6" rel="noopener noreferrer"&gt;Get-Content&lt;/a&gt;. So what I’m doing there is printing out the last line of a log file and wait for newer lines to show up.&lt;/p&gt;

&lt;p&gt;Looks simple now but it took me a while to configure everything I needed, especially the changes to the Application Pool.&lt;/p&gt;

&lt;p&gt;Someday this will all be .NET Core, but right now it’s plain .NET Framework 4.7, thus, the need for a Windows Container.&lt;/p&gt;

&lt;p&gt;When doing this I faced many tasks that are very easy to solve using Windows GUI, but that’s something that’s just not there in containers. So you’ll have to use simple CMD or PowerShell commands. I’m not a PowerShell wiz, I had to learn a lot of stuff but it’s totally worth it, if you’re not familiar with PowerShell yet, you should definitely get a big cup of coffee (or mate) and start playing with it.&lt;/p&gt;

&lt;p&gt;Know how to improve this Dockerfile? please let me know in the comments and I’ll update it accordingly.&lt;/p&gt;

</description>
      <category>dockercompose</category>
      <category>windowscontainers</category>
      <category>docker</category>
      <category>windows</category>
    </item>
    <item>
      <title>Setting up a GitHub page with Jekyll and a Docker container</title>
      <dc:creator>Sebastián Gómez</dc:creator>
      <pubDate>Wed, 28 Nov 2018 13:04:37 +0000</pubDate>
      <link>https://dev.to/sebagomez/setting-up-a-github-page-with-jekyll-and-a-docker-container-56pb</link>
      <guid>https://dev.to/sebagomez/setting-up-a-github-page-with-jekyll-and-a-docker-container-56pb</guid>
      <description>&lt;p&gt;&lt;strong&gt;&lt;em&gt;TL;DR&lt;/em&gt;&lt;/strong&gt; &lt;em&gt;: I built my static personal site (&lt;/em&gt;&lt;a href="https://sebagomez.github.io/" rel="noopener noreferrer"&gt;&lt;em&gt;https://sebagomez.github.io/&lt;/em&gt;&lt;/a&gt;&lt;em&gt;) using a container instead of installing all the needed runtime/build for Jekyll which includes Ruby and who knows what else.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I came across a very cool personal site lately (&lt;a href="https://jarrekk.github.io/Jalpc/" rel="noopener noreferrer"&gt;https://jarrekk.github.io/Jalpc/&lt;/a&gt;) and I thought it was time to revamp my old GitHub Page with something useful. The repo of the site was hosted on GitHub so I thought I could just fork the repo myself and update it with my data. WRONG!&lt;/p&gt;

&lt;p&gt;After forking the repo I realized it was something called Jekyll. I had heard about Jekyll before but had no idea what it was, less how to use it. I started to read a little about it to find out I had to install Ruby. Don’t get me wrong, I have nothing against Ruby, but I don’t want to install anything else on my PC. Especially another runtime/build tools.&lt;/p&gt;

&lt;p&gt;So before deleting the project and forget all about the site, I thought I could spend 2minutes looking for a container with the needed tools. Lucky me! I found the right container (jekyll\jekyll:builder).&lt;/p&gt;

&lt;p&gt;So this is what I did to get my site without knowing anything Jekyl (or Ruby).&lt;br&gt;&lt;br&gt;
The first thing I did was to start a container based on that image, I noticed that &lt;code&gt;jekyll serve&lt;/code&gt; starts a web server in port 4000 so I added the -p flag and the -v to mount my files inside the container. This is the command I ran:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;docker run — rm -v c:/code/sebastian/Jalpc:/srv/jekyll -p 4000:4000 -it jekyll/jekyll:builder bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I created a batch file that fires up the container.&lt;br&gt;&lt;br&gt;
Once inside the container in the bash prompt you could just type &lt;code&gt;_jekyll serve_&lt;/code&gt;. This command will build the static site and fire up a web browser to it on port 4000.&lt;/p&gt;

&lt;p&gt;And that’s it. That’s how you build the site, but now you’ll have to push it to your .github.io repository, so this is my solution… it might be a better one I’m not aware of, so this is what I did.&lt;/p&gt;

&lt;p&gt;The generated static site is located under the _site folder, so I created another batch file called deploy.cmd that does exactly that… it’ll copy the files under _site to another repo in my local machine that has a remote against my sebagomez.github.io repo&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;robocopy \_site\ ..\github.io \*.\* /E /XF \*.cmd \*.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After everything is copied, all I need to do is go to the github.io repo and commit/push the changes.&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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AhXWMTcAGR433Zjl8J-FItw.gif" 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%2Fcdn-images-1.medium.com%2Fmax%2F1024%2F1%2AhXWMTcAGR433Zjl8J-FItw.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Why did I do it that way?&lt;/p&gt;

&lt;p&gt;The problem is the _site folder is ignored in the original repo, and of course, we want to keep it that way. And there’s no (known by me) way of adding another remote repo with a different .gitignore file, so I didn’t know how to solve that. This is the best solution I could come up with, I’m open to suggestions on how to improve this design.&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%2Fcdn-images-1.medium.com%2Fmax%2F822%2F1%2AldOBeIDjHZSY6CatP9ZOkg.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%2Fcdn-images-1.medium.com%2Fmax%2F822%2F1%2AldOBeIDjHZSY6CatP9ZOkg.png"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>githubpages</category>
      <category>docker</category>
      <category>github</category>
      <category>ruby</category>
    </item>
    <item>
      <title>Installing the Docker client on Windows Subsystem for Linux (Ubuntu)</title>
      <dc:creator>Sebastián Gómez</dc:creator>
      <pubDate>Fri, 20 Oct 2017 17:27:55 +0000</pubDate>
      <link>https://dev.to/sebagomez/installing-the-docker-client-on-windows-subsystem-for-linux-ubuntu-3cgd</link>
      <guid>https://dev.to/sebagomez/installing-the-docker-client-on-windows-subsystem-for-linux-ubuntu-3cgd</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedd0o81y8o87yr3681tg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fedd0o81y8o87yr3681tg.png" width="800" height="385"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I'm a PC guy, I have always been. I played around a little bit with Linux back in the university days, but that was it.&lt;/p&gt;

&lt;p&gt;But now, Windows brought Linux a little closer. I don't have to do anything complicated like dual booting or having another computer set up just to experience the Linux (non-GUI) environment.&lt;/p&gt;

&lt;p&gt;As a Windows Insider, I tried the &lt;a href="https://blogs.msdn.microsoft.com/wsl/2016/04/22/windows-subsystem-for-linux-overview/" rel="noopener noreferrer"&gt;Windows Subsystem for Linux&lt;/a&gt; since day 1 and I really enjoyed it.&lt;/p&gt;

&lt;p&gt;Now that Falls Creators Update is out, I'm using the Ubuntu distro from the store, and the first thing I want to do is having the Docker client installed.. It is not rocket science, but I did have some bumps on the road (because of my pretty low knowledge of Linux), so I thought I'd write what I've done to achieve that, in case it could be useful to somebody else.&lt;/p&gt;

&lt;p&gt;There's something you need to understand first. The Docker Engine does not run on WSL, you HAVE to have Docker For Windows installed on your host machine. What we'll end up with at the end of this document is the Docker client running on Linux (WSL) sending commands to your Docker Engine daemon installed on Windows.&lt;/p&gt;

&lt;p&gt;So, open you Ubuntu bash console, the first thing is to install the client. In order to do that, you have to use apt-get, which is Ubuntu's package manager (more info about apt &lt;a href="https://en.wikipedia.org/wiki/APT_(Debian)" rel="noopener noreferrer"&gt;here&lt;/a&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update the apt package index:
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;$ sudo apt-get update&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install packages to allow apt to use a repository over HTTPS:
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;$ sudo apt-get install apt-transport-https ca-certificates curl software-properties-common&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Add Docker’s official GPG key:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -&lt;/code&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Verify that you now have the key with the fingerprint &lt;em&gt;9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88&lt;/em&gt;, by searching for the last 8 characters of the fingerprint.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code&gt;$ sudo apt-key fingerprint 0EBFCD88&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pub 4096R/0EBFCD88 2017–02–22
 Key fingerprint = 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88
uid Docker Release (CE deb) &amp;lt;docker@docker.com&amp;gt;
sub 4096R/F273FCD8 2017–02–22
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Use the following command to set up the stable repository. You always need the stable repository, even if you want to install builds from the edge or test repositories as well. To add the edge or test repository, add the word edge or test (or both) after the word stable in the commands below.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;$ sudo add-apt-repository “deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb\_release -cs) stable”&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now we're ready to install Docker Community Edition&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Update the apt package index again&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;$ sudo apt-get update&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;And install Docker CE&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;$ sudo apt-get install docker-ce&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;When that finishes, you'll end up having everything installed in Linux, but as I mentioned before, the Docker Engine does not run in WSL so if you write any command like &lt;em&gt;docker images&lt;/em&gt;, you'll see a message like this one:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No, it is not running and it'll never be, at least for now.&lt;/p&gt;

&lt;p&gt;You need to tell the Docker client where the Docker host is, and you can do that by using the -H option as follows:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ docker -H localhost:2375 images&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If you don't want to type the host every time, you can set up and environment variable called DOCKER_HOST to localhost:2375&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ export DOCKER\_HOST=localhost:2375&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now just running &lt;code&gt;docker images&lt;/code&gt; will show the images in your host environment.&lt;br&gt;
But, that environment variable will last only as long as the session does. You would have to set it every time you open bash. So, in order to avoid that, you set that variable in a file called .bash_profile in your home directory, like this:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;$ echo “export DOCKER\_HOST=localhost:2375” \&amp;gt;\&amp;gt; ~/.bash\_profile&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Restart the bash console and the DOCKER_HOST variable should be there, just type &lt;/p&gt;

&lt;p&gt;&lt;code&gt;docker images&lt;/code&gt; to check everything is there.&lt;/p&gt;

&lt;p&gt;I hope this post will help others, if it does, let me know.&lt;/p&gt;

&lt;p&gt;EDIT: Make sure you expose the daemon on Windows, otherwise it won't work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftzdymmpl4hdmvizrwi5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftzdymmpl4hdmvizrwi5j.png" width="800" height="521"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;References: &lt;a href="https://docs.docker.com/engine/installation/linux/docker-ce/ubuntu/" rel="noopener noreferrer"&gt;Get Docker CE for Ubuntu&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Special thanks to &lt;a href="https://twitter.com/richturn_ms" rel="noopener noreferrer"&gt;Rich Turner&lt;/a&gt; for his kindness and patience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;EDIT&lt;/strong&gt;: I recently learned there's an official, more complicated but secure way of achieving the same, so I thought I'd share it here: &lt;a href="https://blogs.msdn.microsoft.com/commandline/2017/12/08/cross-post-wsl-interoperability-with-docker/" rel="noopener noreferrer"&gt;WSL Interoperability with Docker&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>wsl</category>
      <category>ubuntu</category>
      <category>windows</category>
    </item>
  </channel>
</rss>
