<?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: Scott Coulton</title>
    <description>The latest articles on DEV Community by Scott Coulton (@scottyc).</description>
    <link>https://dev.to/scottyc</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%2F141196%2F5ad62cbf-84ed-4973-8bb9-9495edf583ca.jpeg</url>
      <title>DEV Community: Scott Coulton</title>
      <link>https://dev.to/scottyc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/scottyc"/>
    <language>en</language>
    <item>
      <title>I cho, cho, choose you container image Part 3.</title>
      <dc:creator>Scott Coulton</dc:creator>
      <pubDate>Tue, 07 May 2019 00:32:23 +0000</pubDate>
      <link>https://dev.to/scottyc/i-cho-cho-choose-you-container-image-part-3-5aj9</link>
      <guid>https://dev.to/scottyc/i-cho-cho-choose-you-container-image-part-3-5aj9</guid>
      <description>&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%2F800%2F1%2Atb63R5ixxprjZ9oKs3eHFA.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%2F800%2F1%2Atb63R5ixxprjZ9oKs3eHFA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the past two posts (&lt;a href="https://dev.to/scottyc/i-cho-cho-chose-you-container-image-part-1-227p"&gt;part 1&lt;/a&gt; and &lt;a href="https://dev.to/scottyc/i-cho-cho-choose-you-container-image-part-2-2ahb"&gt;part 2&lt;/a&gt;) in this series, we have looked at what base images are available to us as developers. Then we tackled compiled languages with Golang. Now in this post, we are going to look at the options available to us using a dynamic language. Before we start we should get something out of the way. If you have been following the series we have spoken about the scratch base image. I have some bad news if you are using a dynamic language, you will not be able to use scratch as you need the runtime installed, unlike compiled languages. So in this post, we are going to use the Full OS, Slim OS and Alpine Linux images. &lt;/p&gt;

&lt;p&gt;If you want to take advantage of multi-stage builds with a dynamic language it is a bit more nuanced. As we won't have a single binary to copy, in saying that we can still use multi-stage builds. Python is actually quite nice to use in multi-stage builds as it has &lt;a href="https://packaging.python.org/guides/installing-using-pip-and-virtualenv/" rel="noopener noreferrer"&gt;virtualenv&lt;/a&gt; which gives use logical separation of dependencies we need to run our application. To use multi-stage build you would copy the virtualenv directory from the build container to the final image. Again as with the Golang example, the application we are using is fairly lightweight. Just a simple Python web server hosting a static HMTL file. If you would like to view the code just go &lt;a href="https://github.com/scotty-c/container-image-examples/blob/master/python/web.py" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;So as mentioned earlier we have three choices with a dynamic language so we will start with the full OS image.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM python:3.8.0a2-stretch as build

RUN python3 -m venv /web

COPY . /web

FROM python:3.8.0a2-stretch

COPY --from=build /web /web

WORKDIR /web

EXPOSE 8080

ENTRYPOINT [ "python", "web]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we build our base image with the Dockerfile above using multi-stage builds we have an image &lt;code&gt;945mb&lt;/code&gt; So as you can see dynamic language container images are much larger than compiled languages due to needing the runtime. Now remembering from our first post this image also contains critical vulnerabilities. So let’s move onto the slim image as see how much of the image size we can save.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM python:3.8.0a2-slim-stretch as build

RUN python3 -m venv /web

COPY . /web

FROM python:3.8.0a2-slim-stretch

COPY --from=build /web /web

WORKDIR /web

EXPOSE 8080

ENTRYPOINT [ "python", "web.py" ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this build using the slim OS as the base image, we get an image size of &lt;code&gt;159mb&lt;/code&gt; So as you can see that is a huge saving in size by swapping from a Full OS image to a slim version of the same OS. Unfortunately, this image still ships with vulnerable packages. So if we move our application to Alpine Linux what benefits do we yield?&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM python:3.8.0a2-alpine3.9 as build

RUN python3 -m venv /web

COPY . /web

FROM python:3.8.0a2-alpine3.9

COPY --from=build /web /web

WORKDIR /web

EXPOSE 8080

ENTRYPOINT [ "python", "web.py" ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now moving to Alpine Linux has given us the smallest image size coming in at &lt;code&gt;103mb&lt;/code&gt; with no critical vulnerabilities. Now we briefly spoke about this issue in &lt;a href="https://dev.to/scottyc/i-cho-cho-chose-you-container-image-part-1-227p"&gt;part 1&lt;/a&gt;. Alpine does not use &lt;code&gt;glibc&lt;/code&gt; instead, it uses &lt;a href="https://www.musl-libc.org/" rel="noopener noreferrer"&gt;&lt;code&gt;musl libc&lt;/code&gt;&lt;/a&gt; now, this is much more important to a dynamic language as if you have dependencies that rely on &lt;code&gt;glibc&lt;/code&gt; you might have issues with Alpine. &lt;/p&gt;

&lt;p&gt;If you want to look at any of the code for this series of posts, please visit my &lt;a href="https://github.com/scotty-c/container-image-examples" rel="noopener noreferrer"&gt;GitHub page&lt;/a&gt;. For further learning about containers or Kubernetes checkout out my &lt;a href="https://github.com/scotty-c/kubernetes-on-azure-workshop" rel="noopener noreferrer"&gt;OSS workshop&lt;/a&gt; or you can always ask me any question on Twitter @scottcoulton&lt;/p&gt;

</description>
      <category>docker</category>
      <category>beginners</category>
      <category>development</category>
      <category>python</category>
    </item>
    <item>
      <title>I cho, cho, choose you container image Part 2.</title>
      <dc:creator>Scott Coulton</dc:creator>
      <pubDate>Tue, 16 Apr 2019 22:34:18 +0000</pubDate>
      <link>https://dev.to/scottyc/i-cho-cho-choose-you-container-image-part-2-2ahb</link>
      <guid>https://dev.to/scottyc/i-cho-cho-choose-you-container-image-part-2-2ahb</guid>
      <description>&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%2F800%2F1%2AhylJ1hGCcixiY4ubbhpkGA.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%2F800%2F1%2AhylJ1hGCcixiY4ubbhpkGA.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the &lt;a href="https://dev.to/scottyc/i-cho-cho-chose-you-container-image-part-1-227p"&gt;first part of this series&lt;/a&gt;, we looked at the different types of images that are available to us to use as our base container images. In this post the second in the series we will look at adding a real application on top of our base image. As mentioned in our earlier post we are going to choose one compiled language, in this case, it will be Golang. In the next post in the series, we will tackle a dynamic language (Python).&lt;/p&gt;

&lt;p&gt;So we are going to take a really simple &lt;a href="https://github.com/scotty-c/container-image-examples/blob/master/golang/web.go" rel="noopener noreferrer"&gt;Golang application&lt;/a&gt; that is basically going to serve a static HTML file. Don't get too caught up in the constructs of the application. The most important thing is that it compiles, is small and is quick to build so we can see what container base image is the best to use.&lt;/p&gt;

&lt;p&gt;Before we choose which OS to start with one of the best practices to start using for a compiled languages is Docker multi-stage builds. What multi-stage builds give us is the ability to build our binary in one container. This will usually include all the build tools as well. Then copy that binary to a fresh container. So ditching all the build tools and unwanted packages you need to run a production application. For more information on multi-stage builds please go &lt;a href="https://docs.docker.com/develop/develop-images/multistage-build/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With all the different base images we will use multi-stage builds to try to keep our deployable image as small as possible. So in each of the Dockerfiles we will compile our Go binary in the build container then use multi-stage build to move it to the last container that will be our deployment artefact. &lt;/p&gt;

&lt;p&gt;Now the first base container image that we will choose is the Full OS because if you are new to containers this will be the easiest to get up and running.&lt;br&gt;
&lt;br&gt;
 &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM golang:1.11-stretch as build

WORKDIR /go/src/github.com/scottyc/webapp

COPY web.go web.go

RUN CGO_ENABLED=0 GOOS=linux go build -o ./bin/webapp github.com/scottyc/webapp


FROM debian:stretch

RUN mkdir -p /web/static/ 

COPY --from=build /go/src/github.com/scottyc/webapp/bin/webapp /usr/bin
COPY index.html /web/static/index.html

WORKDIR /web

EXPOSE 3000

ENTRYPOINT ["webapp"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This Dockerfile will result in an image that is &lt;code&gt;107mb&lt;/code&gt; and remember from the first post had some critical vulnerabilities in the image. Now let’s move onto the slim OS image&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM golang:1.11-stretch as build

WORKDIR /go/src/github.com/scottyc/webapp

COPY web.go web.go

RUN CGO_ENABLED=0 GOOS=linux go build -o ./bin/webapp github.com/scottyc/webapp


FROM debian:stretch-slim

RUN mkdir -p /web/static/ 

COPY --from=build /go/src/github.com/scottyc/webapp/bin/webapp /usr/bin
COPY index.html /web/static/index.html

WORKDIR /web

EXPOSE 3000

ENTRYPOINT ["webapp"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you will notice that we used the full OS still as the build image which is totally fine as we will discard that anyway, this build will result in an image which is &lt;code&gt;61.9mb&lt;/code&gt; in size. So that is quite a reduction without changing any of the application code. We still need to remember the image has vulnerable packages in it. Now let’s try Alpine Linux.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM golang:1.11.2-alpine3.8 as build

WORKDIR /go/src/github.com/scottyc/webapp

COPY web.go web.go

RUN CGO_ENABLED=0 GOOS=linux go build -o ./bin/webapp github.com/scottyc/webapp


FROM alpine:3.8

RUN mkdir -p /web/static/ 

COPY --from=build /go/src/github.com/scottyc/webapp/bin/webapp /usr/bin
COPY index.html /web/static/index.html

WORKDIR /web

EXPOSE 3000

ENTRYPOINT ["webapp"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now this build results in an image size of &lt;code&gt;11mb&lt;/code&gt; and has no vulnerable packages in the image. So as you can see moving to Alpine has greatly decreased the image size and increased our security posture. Last but not least let’s look at scratch.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM golang:1.11.2-alpine3.8 as build
WORKDIR /go/src/github.com/scottyc/webapp
COPY web.go web.go
COPY index.html /web/static/index.html
RUN CGO_ENABLED=0 GOOS=linux go build -o ./bin/webapp github.com/scottyc/webapp
FROM scratch
COPY --from=build /go/src/github.com/scottyc/webapp/bin/webapp /usr/bin/webapp
COPY --from=build /web/static/index.html /web/static/index.html
EXPOSE 3000
ENTRYPOINT ["/usr/bin/webapp"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you will notice that we use Alpine to build our binary as scratch has no tools or package manager. So we will use the build tools in Alpine then move the binary into the scratch container. The scratch container will only contain the Go binary. This will result in an image size of 6.59mb with the best security posture. So as you can see just by choosing a different container base image we have yielded greatly different results with the same application code. If you want to take any of these images for a test drive please visit my &lt;a href="https://github.com/scotty-c/container-image-examples" rel="noopener noreferrer"&gt;Github page&lt;/a&gt;. In the next post in the series, we will look at dynamic languages and use Python.&lt;/p&gt;

&lt;p&gt;For further learning about containers or Kubernetes checkout out my &lt;a href="https://github.com/scotty-c/kubernetes-on-azure-workshop" rel="noopener noreferrer"&gt;OSS workshop&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>beginners</category>
      <category>development</category>
      <category>go</category>
    </item>
    <item>
      <title>Windows for a Linux guy</title>
      <dc:creator>Scott Coulton</dc:creator>
      <pubDate>Wed, 03 Apr 2019 02:23:07 +0000</pubDate>
      <link>https://dev.to/azure/windows-for-a-linux-guy-390p</link>
      <guid>https://dev.to/azure/windows-for-a-linux-guy-390p</guid>
      <description>&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%2F800%2F1%2AFJxoGsG4ZjsPhcfg9qFwjQ.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%2F800%2F1%2AFJxoGsG4ZjsPhcfg9qFwjQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I recently moved to Microsoft for work and got a choice of laptop. I decided to go down the Surfacebook route as a change is as good as a holiday and I had a Dell xps prior. Being a Linux guy (Debian the OS of choice) the first thing I did was dual boot it. Got everything up and running with no issues which was awesome. Then I started to look at &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10?WT.mc_id=wsl-dev.to-sccoulto"&gt;WSL&lt;/a&gt; and I noticed there was a Debian stretch install. I got to wondering how close could I get this to my native Linux setup?&lt;/p&gt;

&lt;p&gt;To give you the context of my Linux setup, I run &lt;a href="https://i3wm.org/" rel="noopener noreferrer"&gt;i3wm&lt;/a&gt;, I run vscode for golang development, I still love vim for everything else, golang as mentioned, azure cli, docker, minikube and last but not least my git bash prompt. If I got all this working I would be pretty happy. As this is going to be a long post I am not going to go through installing git etc as you just use &lt;code&gt;apt-get&lt;/code&gt; for that.&lt;/p&gt;

&lt;p&gt;Before we start there is a disclaimer. As mentioned I am not a Windows expert. So if you are a Windows expert and are reading this and you see something wrong or could be done better. Just hit me up on Twitter and I will update the post and give you credit on the post for your help.&lt;/p&gt;

&lt;p&gt;If you are new to WSL read the docs &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10?WT.mc_id=wsl-dev.to-sccoulto"&gt;here&lt;/a&gt; it will get you started. As mentioned before I am using Debian but I am assuming this setup will work with Ubuntu as well.&lt;/p&gt;

&lt;p&gt;Now let’s start. The first thing on my list was i3wm, the reason I love i3 is its all keyboard based and super efficient when using a terminal. Now I found you can get this working on WSL by installing a x server and forwarding it to a client on the Windows side. I found this to be a little heavy-handed for what I needed so I decided to go with &lt;a href="https://github.com/tmux/tmux/wiki" rel="noopener noreferrer"&gt;tmux&lt;/a&gt; as all I really needed was to be able to manipulate the terminal panes. I found a really good &lt;a href="https://github.com/tmux-plugins/tpm" rel="noopener noreferrer"&gt;package manager&lt;/a&gt; for tmux that allows you to get some really cool features without having a massive &lt;code&gt;.tmux.conf&lt;/code&gt; You can find the list of plugins available here. My &lt;code&gt;.tmux.conf&lt;/code&gt; looks like this&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# list of plugins
set -g @plugin 'tmux-plugins/tpm'
set -g @plugin 'tmux-plugins/tmux-sensible'
set -g @plugin 'tmux-plugins/tmux-online-status'
set -g @plugin 'tmux-plugins/tmux-yank'
set -g @plugin 'tmux-plugins/tmux-pain-control'

# status bar
set -g status-bg red
set -g status-fg white
​
# online check
set -g status-right "Online: #{online_status} | %a %h-%d %H:%M "
​
# Initialize TMUX plugin manager (keep this line at the very bottom of tmux.conf)
run -b '~/.tmux/plugins/tpm/tpm'
​
# mouse stuff
set -g mouse on
set-window-option -g mouse on
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see its really short and gives me the power to manipulate the terminal panes and I have copy and paste with vim keys. Winning! Except you will notice at the right-hand side of the online status that the tick is not showing. This is because the default font &lt;code&gt;consolas&lt;/code&gt; does not have the characters we need. So we will need to install a new font, I chose to use &lt;code&gt;DejaVu Sans Mono&lt;/code&gt; So all you need to do is download and install the font on the Windows OS then right click WSL top bar, select &lt;code&gt;Defaults&lt;/code&gt;, the Font and change the font of the terminal to use &lt;code&gt;DejaVa Sans Mono&lt;/code&gt;. Then the problem is fixed and the terminal also now looks more like a native Linux terminal. If you want tmux to start automatically when WSL opens add this to your &lt;code&gt;.bashrc&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;if [ "$TMUX" = ""]; then tmux -u; fi&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Next cab off the rank will be Docker. Now you can get Docker running natively inside WSL . To accomplish that we will need to do only a few things. Firstly, install Docker for windows (&lt;a href="https://docs.docker.com/docker-for-windows/install/" rel="noopener noreferrer"&gt;instructions here&lt;/a&gt;) While we are in the WSL terminal we will need to add the following to our &lt;code&gt;.bashrc&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;alias docker='docker.exe'&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now if we go back to the WSL terminal and enter &lt;code&gt;docker ps&lt;/code&gt; it should be all working. If not make sure you &lt;code&gt;source .bashrc&lt;/code&gt; What we have done here is alias the &lt;code&gt;docker.exe&lt;/code&gt; binary to docker This will make the setup feel more like a native Linux install of Docker. This has been updated from my original post where we forwarded the Docker daemon over a non-encrypted &lt;code&gt;tcp&lt;/code&gt; port. This new way is more secure.&lt;/p&gt;

&lt;p&gt;Next in line is the Azure cli, that is pretty straightforward follow the instructions &lt;a href="https://docs.microsoft.com/en-us/cli/azure/install-azure-cli-apt?view=azure-cli-latest?WT.mc_id=wsl-dev.to-sccoulto"&gt;here&lt;/a&gt; for Debian. Then run &lt;code&gt;az login&lt;/code&gt; from the terminal to get you up and running.&lt;/p&gt;

&lt;p&gt;We will then install &lt;a href="https://kubernetes.io/docs/tasks/tools/install-kubectl/#install-kubectl" rel="noopener noreferrer"&gt;kubectl&lt;/a&gt; in the Debian terminal with the following instructions.&lt;/p&gt;

&lt;p&gt;The next tool is something I have only found recently but it is so useful it is &lt;code&gt;kubectx&lt;/code&gt; If you have not used it before I would recommend that you check it out and for a quick rundown it basically a tool for managing your Kubernetes clusters credentials in &lt;code&gt;~/.kube/config&lt;/code&gt; file. To install go to the Github page here and follow the installation method for &lt;a href="https://github.com/ahmetb/kubectx#linux" rel="noopener noreferrer"&gt;bash&lt;/a&gt;. We will park this for now but come back to it later as well will use &lt;code&gt;kubectx&lt;/code&gt; in our bash functions to make everything seamless to run.&lt;/p&gt;

&lt;p&gt;The last easy piece of the puzzle was was the bash git prompt. I like this one &lt;a href="https://github.com/magicmonty/bash-git-prompt" rel="noopener noreferrer"&gt;https://github.com/magicmonty/bash-git-prompt&lt;/a&gt; and it's a personal choice but now we have our new font installed everything will work.&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%2F800%2F1%2AXKZlNT4owgPfwlCoYSO1LQ.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%2F800%2F1%2AXKZlNT4owgPfwlCoYSO1LQ.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Vim is also an easy one to install with &lt;code&gt;sudo apt-get install vim&lt;/code&gt; I like to add a few tweaks and install &lt;a href="https://github.com/tpope/vim-pathogen" rel="noopener noreferrer"&gt;pathogen&lt;/a&gt; and &lt;a href="https://github.com/scrooloose/nerdtree" rel="noopener noreferrer"&gt;nerdtree&lt;/a&gt;. Then we will get something like the below image.&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%2F800%2F1%2Aw4vPr4rc-C3dCOBR6aXBBw.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%2F800%2F1%2Aw4vPr4rc-C3dCOBR6aXBBw.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we will move onto the more challenging apps to get working firstly we will tackle minikube. Now to install minikube and get it working on Windows is not difficult, to access it from WSL is also not difficult. I have a workflow that allows me to spin up clusters on Azure or minikube with a single command. I wanted to replicate that workflow. So the two biggest hurdles to getting this working are you have two installations of &lt;code&gt;kubectl&lt;/code&gt; one on the Windows OS and the other on the Debian side. The second is minikube needs to start with admin privileges due to using hyper-v. So let’s run through the solution.&lt;/p&gt;

&lt;p&gt;The first thing I did was create a default switch in hyper-v called minikube. this can be done in the hyper-v manager and click on the &lt;code&gt;virtual switch manager&lt;/code&gt; Then create a new switch called minikube that is an external switch.&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%2F800%2F1%2Axbb4qNtLnwm0qXf8y3irxg.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%2F800%2F1%2Axbb4qNtLnwm0qXf8y3irxg.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To install minikube follow the instructions here using chocolatey. Now we have all the plumbing in place. We need to then open WSL as an administrator otherwise as mentioned earlier we cant execute hyper-v commands. So to do this I just right on the WSL icon and use the &lt;code&gt;run as adminstrator&lt;/code&gt; (i know I need to find a better way to do this) Now let's add some bash aliases. Calling a binary with a &lt;code&gt;.exe&lt;/code&gt; at the end does not feel natural in Linux so the first bash alias will just alias the &lt;code&gt;minikube.exe&lt;/code&gt; binary with &lt;code&gt;minikube&lt;/code&gt; like so &lt;code&gt;alias minikube='minikube.exe&lt;/code&gt; This is for when you are manually typing commands in the terminal. The next is you probably want bash autocompletion as its super handy. Add this to your &lt;code&gt;.bashrc&lt;/code&gt; &lt;br&gt;
&lt;code&gt;source &amp;lt;(minikube.exe completion bash)&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Ok now lets alias creating our minikube node. I have created a file called &lt;code&gt;~/.kubefunc&lt;/code&gt; and I source it from my &lt;code&gt;~/.bash_profile&lt;/code&gt; Its a personal choice but I think it keeps things tidy and easy to update. Here is the code to run the cluster.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
#!/bin/bash
minikube_docker () {
minikube.exe start --memory=8192 --cpus=4 \
  --vm-driver=hyperv \
  --hyperv-virtual-switch=minikube \
  --kubernetes-version=v1.13.0 \
  --bootstrapper=kubeadm \
  --extra-config=apiserver.enable-admission-plugins="LimitRanger,NamespaceExists,NamespaceLifecycle,ResourceQuota,ServiceAccount,DefaultStorageClass,MutatingAdmissionWebhook"
kubectl config set-cluster minikube --server=https://$(minikube.exe ip):8443 --certificate-authority=/mnt/c/Users/sccoulto/.minikube/ca.crt
kubectl config set-context minikube --cluster=minikube --user=minikube
kubectl config set-credentials minikube --client-certificate=/mnt/c/Users/sccoulto/.minikube/client.crt --client-key=/mnt/c/Users/sccoulto/.minikube/client.key
kubectx minikube
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's break it down. So the function is called &lt;code&gt;minikube_docker&lt;/code&gt; ( I have a containerd one as well) We start the server with cpu and memory, use hyper-v as the vm driver, reference the hyper-v switch we created earlier, chose the kubernetes version, use kubeadm to bootstrap the cluster, the next bit is extra config that I pass to the kubelet to be able to test other application on Kubernetes like istio or knative. The last four lines I am getting the cluster credentials from inside the Windows OS and passing them to the local WSL &lt;code&gt;kubectl&lt;/code&gt; and then setting the current context to use &lt;code&gt;minkube&lt;/code&gt; with &lt;code&gt;kubectx&lt;/code&gt; Now we are set to spin up our cluster. So as I mentioned earlier I source the &lt;code&gt;.kubefunc&lt;/code&gt; file from my &lt;code&gt;.bash_profile&lt;/code&gt; so for me its &lt;code&gt;source ~/.bash_profile&lt;/code&gt; Then run &lt;code&gt;minikube_docker&lt;/code&gt; wait a few minutes and you will have a working cluster. To test this just run &lt;code&gt;kubectl get nodes&lt;/code&gt; from inside WSL. Don't forget if copied and pasted the code from above to change sccoulto to your username. One last thing we need to do as a cleanup task is to create another function to delete the cluster and clear it off both our &lt;code&gt;kubectl&lt;/code&gt; configs.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;minikube_delete () {
minikube delete
kubectx -d minikube
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;minikube delete&lt;/code&gt; will clean up the Windows OS side and &lt;code&gt;kubectx -d minikube&lt;/code&gt; cleans up our WSL Debian OS.&lt;/p&gt;

&lt;p&gt;Now we have covered a lot and the end is in sight the last thing to cover is setting up our Go environment. So to be able to use vscode we will install it on Windows as per normal. Then we are going to install go onto the windows OS as per the instructions &lt;a href="https://code.visualstudio.com/docs/setup/windows" rel="noopener noreferrer"&gt;here&lt;/a&gt; but we are going to change a few things like the &lt;code&gt;GOPATH&lt;/code&gt; this is so we have it in a place that we can access it from both the Windows OS and WSL. I created it in my home directory &lt;code&gt;Documents\Development\go&lt;/code&gt; but you can use anywhere in your home directory. We need to add the environment variables to the Windows os under user variables. One for &lt;code&gt;GOPATH&lt;/code&gt; and then point it to the go folder you just created. Then add the &lt;code&gt;bin&lt;/code&gt; directory from inside the new go folder to the path.&lt;/p&gt;

&lt;p&gt;Then we install go on WSL just following the normal Linux instructions here. We will then add the following to our &lt;code&gt;~/.bash_profile&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;# golang
export GOROOT=/usr/local/go
export GOBIN=/mnt/c/Users/sccoulto/Documents/Development/go/bin
export GOPATH=/mnt/c/Users/sccoulto/Documents/Development/go
export PATH="$PATH:/usr/local/go/bin:/mnt/c/Users/sccoulto/Documents/Development/go/bin"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now we are pointing both installations at the same folders. Now for our last setting in vscode. I want to use the WSL terminal in vscode so I need to change the default terminal under user settings to &lt;code&gt;bash.exe&lt;/code&gt;&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%2F800%2F1%2AIGDQf06HVPEApN5u4xuNKw.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%2F800%2F1%2AIGDQf06HVPEApN5u4xuNKw.jpeg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now we are done, so I think we have got really close to a native Linux feel on Windows. There are a few bumps that you will encounter on the way and it is a little bit slower than native Linux. But if you are a Windows engineer wanting to learn Linux or a Linux guy with a Windows laptop this is a very solid solution. As for the surface book after two weeks I am happy with it, the keyboard and screen are amazing.&lt;/p&gt;

&lt;p&gt;Just a final word, a big shout out to all that work on the WSL project. Really awesome work !!! Also to all the other opensource developers mentioned in this post. Your hard work is greatly appreciated&lt;/p&gt;

</description>
      <category>linux</category>
      <category>windows</category>
      <category>development</category>
      <category>beginners</category>
    </item>
    <item>
      <title>I cho, cho, choose you container image Part 1.</title>
      <dc:creator>Scott Coulton</dc:creator>
      <pubDate>Sun, 31 Mar 2019 22:55:09 +0000</pubDate>
      <link>https://dev.to/scottyc/i-cho-cho-chose-you-container-image-part-1-227p</link>
      <guid>https://dev.to/scottyc/i-cho-cho-chose-you-container-image-part-1-227p</guid>
      <description>&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%2Fzdnet4.cbsistatic.com%2Fhub%2Fi%2Fr%2F2015%2F12%2F08%2Fbcdcf7e6-e974-4cd4-a6ea-e4cf766989a5%2Fthumbnail%2F770x578%2Fa988ca1561a24f749fbbfd7de069858e%2Fshipping-containers.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%2Fzdnet4.cbsistatic.com%2Fhub%2Fi%2Fr%2F2015%2F12%2F08%2Fbcdcf7e6-e974-4cd4-a6ea-e4cf766989a5%2Fthumbnail%2F770x578%2Fa988ca1561a24f749fbbfd7de069858e%2Fshipping-containers.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I first started my journey into using Docker and Kubernetes, one of the issues I hit was “what base image do I use for my applications?” There are so many options out there. For example, I love Debian, that is what I run on my laptop so do I chose Debian because its what I know? That seems pretty straight forward to make that decision but like with everything in life with the choices we make there are repercussions. As a developer, you want to be armed with the best knowledge to why you made the base image choice. Not only for your applications performance or deployment image size but also things like security. &lt;/p&gt;

&lt;p&gt;I am going to break down our applications into two different groups compiled languages like Go or Rust. The other dynamic languages like Python, Ruby or node.js. In this series posts, I am going to use two examples a Go app in part 2 and a Python app in part 3.&lt;/p&gt;

&lt;p&gt;But let's look at the options we have for a base image first. We have four choices a full OS image like Debian, there are also slim versions of full OS’s, next is alpine and last but not least scratch.&lt;/p&gt;

&lt;p&gt;So in the post, I will not call out anyone OS vendor as being better or worse as it is a personal choice. So we will class Full OS’s, Slim OS’s, Alpine and scratch as individual groups. &lt;/p&gt;

&lt;p&gt;Let’s start with full Os’s they are the easiest to get started with and most likely the easiest way to get your application up and running as they contain the most packages installed by default. In part 1 of the series, we are just going to compare the images and not worry about the application just yet. One thing that stands out straight away in the full OS’s images is they ship with vulnerable packages out of the box. Now, these are might not be show stoppers for you, you might have risk mitigation in place to use these images. The information about the state of an image is freely available on DockerHub under the tag information. Below is an example.&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%2F800%2F1%2A7AhjBjJBl-zJsuMtbpx1uw.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%2F800%2F1%2A7AhjBjJBl-zJsuMtbpx1uw.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see there are quite a few critical vulnerabilities that are being deployed before you even add your code. Now let’s move onto our slim images. As it stands now only Debian has a slim image, but what is a slim image? It is a cut down version of the full image with just the base packages it expects that you install any packages you need for your application. By using a slim image you can save about 50% on your image size, for example, the full OS image would be around 100mb and slim is about 54mb.&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%2F800%2F1%2AcIKTiJIncJJlZdLYeLJdgQ.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%2F800%2F1%2AcIKTiJIncJJlZdLYeLJdgQ.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see from your image security scan we have cut down the vulnerable packages. Unfortunately, there are still two critical packages. Next, we will move on to &lt;a href="https://alpinelinux.org/" rel="noopener noreferrer"&gt;Alpine Linux&lt;/a&gt;. This OS was built from the ground up to be a container native OS. The main change in this OS to a traditional OS image (fat or slim) is Alpine does not use glibc instead it uses &lt;a href="https://www.musl-libc.org/" rel="noopener noreferrer"&gt;musl libc&lt;/a&gt;. This is important to know if your application depends on glibc. Alpine Linux by default comes with only the base packages anything your application needs you will have to install. On the upside, the Alpine is just under 6mb for the image.&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%2F800%2F1%2Azrq9C4JYHre2M8aQ2e6LYA.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%2F800%2F1%2Azrq9C4JYHre2M8aQ2e6LYA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see from our vulnerability scan there are no critical vulnerabilities in this image. Alpine can be a little tricky to get used to at first as it has its own package manager that you need to learn. If you persist with it I think the benefits will be worth your time. Lastly, we will look at scratch. What is scratch? Scratch is the starting point for all container images. Using the scratch “image” signals to the build process that you want the next command in the Dockerfile to be the first filesystem layer in your image. So there is no package managers or packages. It's just an empty layered file system. You can pull scratch as it is a reserved namespace. Nor will there be any vulnerable packages as there are no packages by default.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FROM scratch
ADD rootfs.tar.xz /
CMD ["bash"]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Above is an example of a full OS images Dockerfile as you can they all start from scratch.&lt;/p&gt;

&lt;p&gt;In the next post in this series we will take the learnings from this post and apply them to a real application written in GO. &lt;/p&gt;

&lt;p&gt;If you would like to learn more about containers or Kubernetes head to my &lt;a href="https://github.com/scotty-c/kubernetes-on-azure-workshop" rel="noopener noreferrer"&gt;GitHub page&lt;/a&gt; for an open-sourced workshop.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>beginners</category>
      <category>python</category>
      <category>go</category>
    </item>
    <item>
      <title>Understanding application routing in Istio</title>
      <dc:creator>Scott Coulton</dc:creator>
      <pubDate>Fri, 01 Mar 2019 03:45:50 +0000</pubDate>
      <link>https://dev.to/azure/understanding-application-routing-inistio-4dg0</link>
      <guid>https://dev.to/azure/understanding-application-routing-inistio-4dg0</guid>
      <description>&lt;p&gt;In this blog, we will look at how to deploy two versions of the same application and route traffic on weight. This can come in super handy to test a new version of your application on a test percentage of users or more generally for full blue/green deployments. &lt;br&gt;
First thing is first we need a kubernetes cluster, to build that we will use the following &lt;a href="https://docs.microsoft.com/azure/aks/kubernetes-walkthrough?WT.mc_id=docs-dev.to-sccoulto"&gt;docs&lt;/a&gt; or use the following code. If you don't have an Azure account you can get a free trial &lt;a href="https://azure.microsoft.com/offers/ms-azr-0044p/?WT.mc_id=docs-dev.to-sccoulto"&gt;here&lt;/a&gt;. Make sure you have run the az login command before any other commands.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az group create --name k8s --location eastus&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az aks create --resource-group k8s \​
    --name k8s \​
    --generate-ssh-keys \​
    --kubernetes-version 1.12.5 \​
    --enable-rbac \​
    --node-vm-size Standard_DS2_v2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will create our resource group and then our kubernetes cluster if you have kubectl installed then skip the next step. If not install the binary with the following command ​​&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az install aks-cli&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now to set up kubectl with our credentials. We will do that with the following command. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;az aks get-credentials --resource-group k8s --name k8s&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now we have our cluster up and running we will deploy Istio via &lt;a href="https://docs.microsoft.com/en-us/azure/aks/kubernetes-helm?WT.mc_id=docs-dev.to-sccoulto"&gt;Helm&lt;/a&gt;. In this blog, we are not going to dive into Helm. If you want to learn more please click the link above. Now to get you up and running quickly I have created a script to install helm and Istio.&lt;br&gt;
&lt;br&gt;
 &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/bash

if [[ "$OSTYPE" == "linux-gnu" ]]; then
    OS="linux"
    ARCH="linux-amd64"
elif [[ "$OSTYPE" == "darwin"* ]]; then
    OS="osx"
    ARCH="darwin-amd64"
fi    

ISTIO_VERSION=1.0.4
HELM_VERSION=2.11.0

check_tiller () {
POD=$(kubectl get pods --all-namespaces|grep tiller|awk '{print $2}'|head -n 1)
kubectl get pods -n kube-system $POD -o jsonpath="Name: {.metadata.name} Status: {.status.phase}" &amp;gt; /dev/null 2&amp;gt;&amp;amp;1 | grep Running
}

pre_reqs () {
curl -sL "https://github.com/istio/istio/releases/download/$ISTIO_VERSION/istio-$ISTIO_VERSION-$OS.tar.gz" | tar xz
if [ ! -f /usr/local/bin/istioctl ]; then  
    echo "Installing istioctl binary"
    chmod +x ./istio-$ISTIO_VERSION/bin/istioctl
    sudo mv ./istio-$ISTIO_VERSION/bin/istioctl /usr/local/bin/istioctl
fi           

if [ ! -f /usr/local/bin/helm ]; then  
    echo "Installing helm binary"
    curl -sL "https://storage.googleapis.com/kubernetes-helm/helm-v$HELM_VERSION-$ARCH.tar.gz" | tar xz
    chmod +x $ARCH/helm 
    sudo mv linux-amd64/helm /usr/local/bin/
fi    
}    

install_tiller () {
echo "Checking if tiller is running"
check_tiller
if [ $? -eq 0 ]; then
    echo "Tiller is installed and running"
else
echo "Deploying tiller to the cluster"
cat &amp;lt;&amp;lt;EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
  name: tiller
  namespace: kube-system
---
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
  name: tiller
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: cluster-admin
subjects:
  - kind: ServiceAccount
    name: tiller
    namespace: kube-system
EOF
helm init --service-account tiller
fi           
check_tiller
while [ $? -ne 0 ]; do
  echo "Waiting for tiller to be ready"
  sleep 30
done

}

install () {
echo "Deplying istio"

helm install istio-$ISTIO_VERSION/install/kubernetes/helm/istio --name istio --namespace istio-system \
    --set global.controlPlaneSecurityEnabled=true \
    --set grafana.enabled=true \
    --set tracing.enabled=true \
    --set kiali.enabled=true

if [ -d istio-$ISTIO_VERSION ]; then 
    rm -rf istio-$ISTIO_VERSION
  fi    
}

pre_reqs
install_tiller
install
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Make sure all the Istio pods are running&lt;br&gt;
&lt;br&gt;
 &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAMESPACE      NAME                                      READY   STATUS    RESTARTS   AGE
istio-system   grafana-546d9997bb-9mmmn                  1/1     Running   0          4m32s
istio-system   istio-citadel-5c9544c886-hplv6            1/1     Running   0          4m31s
istio-system   istio-egressgateway-6f9db5ff8d-9lgsd      1/1     Running   0          4m32s
istio-system   istio-galley-8dcbb5f99-gf44n              1/1     Running   0          4m32s
istio-system   istio-ingressgateway-6c6b9f9c55-mm82k     1/1     Running   0          4m32s
istio-system   istio-pilot-74984d9cf5-49kj9              2/2     Running   0          4m31s
istio-system   istio-policy-6dd4496b8c-p9s2h             2/2     Running   0          4m31s
istio-system   istio-sidecar-injector-6bd4d9487c-hhwqb   1/1     Running   0          4m31s
istio-system   istio-telemetry-7bb4ffcd9d-5f2bf          2/2     Running   0          4m31s
istio-system   istio-tracing-6445d6dbbf-65mwt            1/1     Running   0          4m31s
istio-system   kiali-ddf8fbbb-sjklt                      1/1     Running   0          4m31s
istio-system   prometheus-65d6f6b6c-8bgzm                1/1     Running   0          4m31s
kube-system    coredns-754f947b4-2r565                   1/1     Running   0          14m
kube-system    coredns-754f947b4-d5pdf                   1/1     Running   0          18m
kube-system    coredns-autoscaler-6fcdb7d64-q245b        1/1     Running   0          18m
kube-system    heapster-5fb7488d97-v45pc                 2/2     Running   0          18m
kube-system    kube-proxy-gpxvg                          1/1     Running   0          14m
kube-system    kube-proxy-rdrxl                          1/1     Running   0          14m
kube-system    kube-proxy-sc9q6                          1/1     Running   0          14m
kube-system    kube-svc-redirect-5t75d                   2/2     Running   0          14m
kube-system    kube-svc-redirect-6bzz8                   2/2     Running   0          14m
kube-system    kube-svc-redirect-jntkv                   2/2     Running   0          14m
kube-system    kubernetes-dashboard-847bb4ddc6-6vxn4     1/1     Running   1          18m
kube-system    metrics-server-7b97f9cd9-x59p2            1/1     Running   0          18m
kube-system    tiller-deploy-6f6fd74b68-rf2lf            1/1     Running   0          5m20s
kube-system    tunnelfront-8576f7d885-tzhnw              1/1     Running   0          18m
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now we are ready to deploy our application. Our application will consist of a simple one-page web application. We are going to have two versions of this application v1 and v2. For this post, we are going to route the traffic equally between both. If this was a production environment you might want to only canary 5% of the traffic to the new version of your application to see how users like it etc. &lt;br&gt;
The first thing we are going to do is mark the default namespace to have Istio automatically inject the envoy proxy. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl label namespace default istio-injection=enabled&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now in my opinion, if this was a production environment I would create a new namespace for the application and have the proxy auto inject.&lt;/p&gt;

&lt;p&gt;The next thing to do is deploy our application. We will do this using the standard&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Kuberntes deployment type.
cat &amp;lt;&amp;lt;EOF | kubectl apply -f - 
apiVersion: v1
kind: Service
metadata:
  name: webapp
  labels:
    app: webapp
spec:
  ports:
  - port: 3000
    name: http
  selector:
    app: webapp
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: webapp-v1
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: webapp
        version: v1
    spec:
      containers:
      - name: webapp
        image: scottyc/webapp:v1
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 3000
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: webapp-v2
spec:
  replicas: 1
  template:
    metadata:
      labels:
        app: webapp
        version: v2
    spec:
      containers:
      - name: webapp
        image: scottyc/webapp:v2
        imagePullPolicy: IfNotPresent
        ports:
        - containerPort: 3000
EOF
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You will notice within this deployment we are deploying v1 and v2 of our application. &lt;/p&gt;

&lt;p&gt;Once our deployment is up and running we have to add a destination rule so Istio knows about our application. Istio will now internally assign a DNS name to the application. The name will be made up of the application name, hostname (taken from our deployment below) and namespace. It will be appended like so .svc.cluster.local.&lt;br&gt;
&lt;br&gt;
 &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: webapp
spec:
  host: webapp
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
EOF
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Now we will create the Istio gateway. This will define the inbound port the application will be listening on and the hosts we will route to. In our case, it will be port 80  and we will use a * to hit any host. We are also going to tie our gateway to the default Istio ingress gateway.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: webapp-gateway
spec:
  selector:
    istio: ingressgateway # use istio default controller
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - "*"
EOF
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Lastly, we will create our Istio virtual service. This defines how we are going to route the traffic on weight. As I mentioned before we are going to weight the traffic 50/50 but have a play around here and change the numbers. This will give you a really good grasp on the mechanics under the hood.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat &amp;lt;&amp;lt;EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: webapp
spec:
  hosts:
  - "*"
  gateways:
  - webapp-gateway
  http:
  - route:
    - destination:
        host: webapp
        subset: v1
      weight: 50 
    - destination:
        host: webapp
        subset: v2
      weight: 50
EOF
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we have everything deployed and our application is accessible to the internet. To get the public IP of the Istio gateway use the following.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;kubectl get svc istio-ingressgateway -n istio-system -o jsonpath="&lt;br&gt;
{.status.loadBalancer.ingress[0].ip}"​&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now use that public IP in your browser and you should get one version of the application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fAFxuJeI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/2dv6gl78selwpxuk3q38.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fAFxuJeI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/2dv6gl78selwpxuk3q38.png" alt="image1"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then use an incognito window and the same public ip address and you should get the other version&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QdesZWqL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/gh7skk9sio75gmpttyo9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QdesZWqL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/gh7skk9sio75gmpttyo9.png" alt="image2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now if you get the same version just close the incognito window and try again.&lt;/p&gt;

&lt;p&gt;This was a basic example of what Istio can do. If you want to read more on Istio and its traffic rule configuration the official docs are here&lt;/p&gt;

</description>
      <category>azure</category>
      <category>aks</category>
      <category>kubernetes</category>
      <category>istio</category>
    </item>
  </channel>
</rss>
