<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="3.9.0">Jekyll</generator><link href="https://jonknopp.com/feed.xml" rel="self" type="application/atom+xml" /><link href="https://jonknopp.com/" rel="alternate" type="text/html" /><updated>2021-02-22T18:33:14-07:00</updated><id>https://jonknopp.com/feed.xml</id><title type="html">JonKnopp.com</title><subtitle>Solution Lead @ BlueModus</subtitle><author><name>Jon Knopp</name></author><entry><title type="html">Other Recommended Blogs for .NET Developers</title><link href="https://jonknopp.com/dotnet/Other-Recommended-Blogs-for-NET-Developers/" rel="alternate" type="text/html" title="Other Recommended Blogs for .NET Developers" /><published>2020-12-28T01:00:00-07:00</published><updated>2020-12-28T01:00:00-07:00</updated><id>https://jonknopp.com/dotnet/Other-Recommended-Blogs-for-NET-Developers</id><content type="html" xml:base="https://jonknopp.com/dotnet/Other-Recommended-Blogs-for-NET-Developers/">&lt;p&gt;Here is a list of other blogs that I recommend following for any developers in the .NET space, in no particular order.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;a href=&quot;https://markus.oberlehner.net/&quot;&gt;Markus Oberlehner&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://wildermuth.com/&quot;&gt;Shawn Wildermuth&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://ardalis.com/blog&quot;&gt;Steve Smith&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://css-tricks.com/&quot;&gt;CSS Tricks&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://jimmybogard.com/&quot;&gt;Jimmy Bogard&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.stevejgordon.co.uk/&quot;&gt;Steve Gordon&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://nodogmablog.bryanhogan.net/&quot;&gt;Bryan Hogan&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.kevindockx.com/?m=all&quot;&gt;Kevin Dockx&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://samlearnsazure.blog/&quot;&gt;Sam Smith&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://www.thereformedprogrammer.net/&quot;&gt;Jon Smith&lt;/a&gt;&lt;/li&gt;
  &lt;li&gt;&lt;a href=&quot;https://azure4everyone.com/&quot;&gt;Azure 4 Everyone&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><author><name>Jon Knopp</name></author><category term="DotNet" /><category term="dotnet" /><summary type="html">Here is a list of other blogs that I recommend following for any developers in the .NET space, in no particular order.</summary></entry><entry><title type="html">Randomly Select Item from Array Based on Frequency</title><link href="https://jonknopp.com/javascript/Randomly-Select-Item-from-Array-Based-on-Frequency/" rel="alternate" type="text/html" title="Randomly Select Item from Array Based on Frequency" /><published>2020-12-12T10:40:00-07:00</published><updated>2020-12-12T10:40:00-07:00</updated><id>https://jonknopp.com/javascript/Randomly-Select-Item-from-Array-Based-on-Frequency</id><content type="html" xml:base="https://jonknopp.com/javascript/Randomly-Select-Item-from-Array-Based-on-Frequency/">&lt;p&gt;While working on a clients project to develop a JavaScript game based around the catching of falling objects, we needed a way to determine the frequency at which objects would fall, in relation to one another. Meaning some “rarer” objects needed to fall less frequently than other “common” objects, while still mainting a random nature to the generation.&lt;/p&gt;

&lt;p&gt;Doing some research into algorithms, I found the following example on &lt;a href=&quot;https://www.geeksforgeeks.org/random-number-generator-in-arbitrary-probability-distribution-fashion&quot;&gt;generating a random number based on an arbitrary probability distribution&lt;/a&gt;. While this sounds quite complicated, it’s really a pretty simple concept. You have 2 sets of data, 1 is the set you are looking to generate randomly from, the other dataset is arbitrary numbers representing the frequency of each item in the first dataset occuring. The number is arbirary because it only determines frequency in relation to the other numbers in the frequency dataset. Bigger numbers occur more than smaller numbers, and this is exactly what we needed to weight our “rarer” objects to occur less often.&lt;/p&gt;

&lt;p&gt;The article had some good insights into how to accomplish the task at hand, while maintaining O(n) complexity. The following code is my JavaScirpt implementation of the algorithm along with an example of how it could be used.&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Utility function to find index of {random} in prefix[start..end]&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;findRandomInPrefixArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;mid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;end&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;random&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;mid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mid&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nx&quot;&gt;end&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;mid&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;start&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Returns a random item from array[]&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// according to distribution array&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// defined by frequency[].&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;export&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;arrayItemArbitraryProbabilityDistribution&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;frequency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;length&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Create and fill prefix array&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;prefix&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[];&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;frequency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;++&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nx&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;frequency&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;c1&quot;&gt;// prefix[n-1] is sum of all frequencies. &lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Generate a random number with  &lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// value from 1 to this sum  &lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;random&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;floor&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Math&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;323567&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)))&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;%&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;])&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// Find find index of {random} in prefix array&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;findRandomInPrefixArray&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;random&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;array&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;index&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And how it might be used:&lt;/p&gt;
&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;// Define our array of object we want to randomly select from&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;fallingItems&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 
&lt;span class=&quot;p&quot;&gt;[{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;150&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;rare.png&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;velocity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;5000&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;25&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;average.png&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;velocity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2000&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;110&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;},&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;common.png&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;'&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;velocity&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;900&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;50&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}];&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// Define the freqeuncy we want each of the fallingItems to be occur at, &lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// relative to one another&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;frequencyOfFallingItems&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;8&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;// Randomly get falling item based on frequency array&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;const&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;itemToQueue&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
    &lt;span class=&quot;nx&quot;&gt;arrayItemArbitraryProbabilityDistribution&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;fallingItems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nx&quot;&gt;frequencyOfFallingItems&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We define an array of 3 items: rare, average, and common. Then we assign the frequencies such that ‘average’ items are twice as likely as ‘rare’ items, and ‘common’ items are twice as likely as ‘average’ items, making them 4 times more likely than ‘rare’ items.&lt;/p&gt;

&lt;p&gt;Questions, comments or thoughts? Feel free to contact me, or discuss on the &lt;a href=&quot;https://gist.github.com/jknopp/18bc605e325742457fbd486c1ab81bf8&quot;&gt;gist&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hope you learned something with me; till next time.&lt;/p&gt;</content><author><name>Jon Knopp</name></author><category term="JavaScript" /><category term="javascript" /><category term="algorithms" /><summary type="html">While working on a clients project to develop a JavaScript game based around the catching of falling objects, we needed a way to determine the frequency at which objects would fall, in relation to one another. Meaning some “rarer” objects needed to fall less frequently than other “common” objects, while still mainting a random nature to the generation.</summary></entry><entry><title type="html">My Cross Platform Development Environment</title><link href="https://jonknopp.com/docker/My-Cross-Platform-Development-Environment/" rel="alternate" type="text/html" title="My Cross Platform Development Environment" /><published>2020-12-09T10:40:00-07:00</published><updated>2020-12-09T10:40:00-07:00</updated><id>https://jonknopp.com/docker/My-Cross-Platform-Development-Environment</id><content type="html" xml:base="https://jonknopp.com/docker/My-Cross-Platform-Development-Environment/">&lt;h1 id=&quot;setting-up-a-cross-platform-development-environment-which-works-on-windows-mac-and-linux&quot;&gt;Setting up a cross-platform development environment which works on Windows, Mac, and Linux.&lt;/h1&gt;

&lt;p&gt;https://chimerical.ca/posts/creating-my-awesome-windows-10-dev-setup&lt;/p&gt;</content><author><name>Jon Knopp</name></author><category term="Docker" /><category term="docker" /><category term="dotnet" /><category term="powershell" /><category term="zsh" /><category term="vscode" /><summary type="html">Setting up a cross-platform development environment which works on Windows, Mac, and Linux.</summary></entry><entry><title type="html">A Windows Docker Container Series (Part 2)</title><link href="https://jonknopp.com/docker/A-Windows-Docker-Container-Series-(Part-2)/" rel="alternate" type="text/html" title="A Windows Docker Container Series (Part 2)" /><published>2017-10-05T03:31:00-06:00</published><updated>2017-10-05T03:31:00-06:00</updated><id>https://jonknopp.com/docker/A-Windows-Docker-Container-Series-(Part-2)</id><content type="html" xml:base="https://jonknopp.com/docker/A-Windows-Docker-Container-Series-(Part-2)/">&lt;p&gt;After &lt;a href=&quot;https://laughlin.github.io/A-Windows-Docker-Container-Series-(Part-1)&quot;&gt;Part 1&lt;/a&gt; where we created a build template in Packer for a Docker compatible image of Windows Server, capable of running containers, I was inspired by the &lt;a href=&quot;https://github.com/dockersamples/dotnet-album-viewer&quot;&gt;West Wind Album Viewer&lt;/a&gt; sample project, and decided it was time to start developing a containerized app for the server to run. With &lt;a href=&quot;https://docs.microsoft.com/en-us/aspnet/core/publishing/visual-studio-tools-for-docker&quot;&gt;Visual Studio 2017&lt;/a&gt; and .NET Framework 4.7, there is native support for running containerized applications with Docker.&lt;/p&gt;

&lt;p&gt;From the &lt;a href=&quot;https://docs.docker.com/docker-for-windows/install/#download-docker-for-windows&quot;&gt;Docker for Windows&lt;/a&gt; website: “Docker for Windows requires 64bit Windows 10 Pro with Hyper-V available”, but I opted for Enterprise which worked fine also. The trick for me was enabling Hyper-V nested virtualization since my Windows 10E image is running in a VM, and also needs the “Virtualization”, and “Containerization” Windows Features enabled, which I will cover more on later. Visual Studio 2017 also contains a native template for .NET Core 2.0 Web API Projects with Docker support via Docker Compose. The goal is to combine this with their Angular Template and a Docker SQL Server container to create a 3 container app debuggable from Visual Studio and SSMS.&lt;/p&gt;

&lt;h4 id=&quot;an-introduction-to-visual-studio-with-docker&quot;&gt;An Introduction to Visual Studio with Docker&lt;/h4&gt;
&lt;p&gt;In order to run Docker and Visual Studio together you must have the following prerequisites: Install Microsoft Visual Studio 2017 with the .NET Core workload and setup &lt;a href=&quot;https://docs.docker.com/docker-for-windows/#shared-drives&quot;&gt;Shared Drives&lt;/a&gt; in Docker for Windows. With a new project, there are 2 ways to add docker support to you .NET Core project: 1) Using Visual Studio, create a new ASP.NET Core Web Application. When the application is loaded, either select Add Docker Support from the Project Menu or 2) right-click the project from the Solution Explorer and select Add &amp;gt; Docker Support. In this solution, we will use both ways.&lt;/p&gt;
&lt;h4 id=&quot;enabling-support-for-docker-inside-a-hyper-v-vm&quot;&gt;Enabling support for Docker inside a Hyper-V VM&lt;/h4&gt;
&lt;p&gt;One of the tricks I face in getting docker working with Visual Studio was compatibility for Docker for Windows inside a Hyper-V VM. Since I wanted to create as much of this project in an automated format as I could, I opted to use fresh VMs for the different steps of the project. This allows me the reparability and reliance we discussed in Part 1. With that comes a catch, Docker for Windows requires Hyper-V Virtualization in order to run containers, which means Nested Virtualization for me since my Windows 10E instance is already running inside a Hyper-V VM. Luckily, I was able to find this &lt;a href=&quot;http://techgenix.com/docker-and-containers-part5/&quot;&gt;post&lt;/a&gt; which had the following solution to enabling Nested Virtualization in Hyper-V:&lt;/p&gt;
&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;Set-VMProcessor&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-VMName&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;ContainerVM01&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-ExposeVirtualizationExtensions&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;bp&quot;&gt;$true&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;how-i-want-to-setup-the-project&quot;&gt;How I want to setup the project&lt;/h3&gt;
&lt;p&gt;As mentioned above, the goal I set out to achieve with this solution was 2 different projects, 1 angular front-end container, and 1 back-end API container that would be networked together to allow for communication. Finally I wanted to run &lt;a href=&quot;https://docs.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker&quot;&gt;SQL Server&lt;/a&gt; as a database solution inside a third container which would be networked with the API container. Since Visual Studio &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/multi-container-microservice-net-applications/multi-container-applications-docker-compose&quot;&gt;natively uses Docker Compose&lt;/a&gt; for multi-container apps, I also wanted to craft my solution in such a way that all the Visual Studio Debugging tools and SQL Server Management functions still worked liked a traditional .NET application.&lt;/p&gt;

&lt;h3 id=&quot;walkthrough&quot;&gt;Walkthrough&lt;/h3&gt;
&lt;h4 id=&quot;setting-up-the-projects&quot;&gt;Setting up the Projects&lt;/h4&gt;
&lt;p&gt;To start of I created the Web API project using the Visual Studio Project Menu. From the menu, I used option #1 from above to enable support for Docker directly when the project was created. What this does is creates a Dockerfile and a docker-compose.yml file which can be used with the Docker engine to run your application inside a container. For the Angular project which is presented in the Project Menu the Docker Support menu is not enabled so I started off creating this project without it. I then used option #2 from above to enable the Docker Support later. More on that, and the SQL Server container to come. 
Breakdown of tiers:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Tier&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Visual Studio Docker Support&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Container Support&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Angular&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Yes, but not natively&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Yes&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Web API&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Yes, natively&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Yes&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;SQL Server&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Not Available&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Yes&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;As noted by the chart, the SQL Server container will not have a Visual Studio project but will be contained within the Visual Studio solutions docker-compose.yml file so that it is run with the solution when debugging.&lt;/p&gt;

&lt;h4 id=&quot;should-i-run-linux-containers-or-windows-containers&quot;&gt;Should I run Linux Containers or Windows Containers?&lt;/h4&gt;
&lt;p&gt;Windows supports the ability to develop and run both Linux-based and Windows-based containers, however, I don’t believe there is a way to develop for both simultaneously in the same solution. When starting off I chose Windows-based containers however, I quickly decided this wasn’t a good choice and started the solution over as Linux-based. The reason I chose this was because my front-end container is being created in Angular and could benefit from having NodeJS running. Also, being a backend developer by trade, I like the idea that the frontend project would be completely changed, and modified (even ported to another language) without affecting any of the API logic. Trying to install NodeJS fully from Powershell in a Dockerfile was proving extremely cumbersome so I opted for Linux in favor of a simple Bash install:&lt;/p&gt;
&lt;div class=&quot;language-dockerfile highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;apt-get update  
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;apt-get &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt;  
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; wget gnupg
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;wget &lt;span class=&quot;nt&quot;&gt;-qO-&lt;/span&gt; https://deb.nodesource.com/setup_8.x | bash -  
&lt;span class=&quot;k&quot;&gt;RUN &lt;/span&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-y&lt;/span&gt; build-essential nodejs
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;SQL Server is available as a &lt;a href=&quot;https://hub.docker.com/r/microsoft/mssql-server-linux/&quot;&gt;Linux container&lt;/a&gt; and .NET Core 2.0 is also compatible on Linux so for this solution it seemed like the right fit.&lt;/p&gt;

&lt;h4 id=&quot;the-api-project&quot;&gt;The API Project&lt;/h4&gt;
&lt;p&gt;In the name of keeping things simple and straightforward at this point in the tutorial, I have the left the API project very close to what was auto-generated, with a few exceptions:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;In the sampledatacontroller.cs class I have the attributes:&lt;/li&gt;
  &lt;li&gt;[EnableCors(“CorsPolicy”)] - needed to allow calls from another container&lt;/li&gt;
  &lt;li&gt;[Route(“api/[controller]”)] - setup our API prefix&lt;/li&gt;
  &lt;li&gt;In the startup.cs file I added:
    &lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddCors&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;options&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;options&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AddPolicy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;CorsPolicy&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
  	&lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;builder&lt;/span&gt;
      			&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AllowAnyOrigin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AllowAnyMethod&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AllowAnyHeader&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
                  &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;AllowCredentials&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&quot;the-angular-project&quot;&gt;The Angular Project&lt;/h4&gt;
&lt;p&gt;This project was the trickiest to get running in a Docker container. As mentioned above, I had to add the bash script lines to the generate Dockerfile. I also had to update the ClientApp\app\components\fetchdata\fetchdata.component.ts file to account for the API call instead of a local call. In addition to updating the call I also added an app.config.ts file to ClientApp\app\ which held the variable ‘apiBaseUrl’ in a class, so that the “http://localhost:PORT/ value could be configurable and global. The reason this project is separated is because it is still served by .NET Core, meaning it uses Startup.cs, Program.cs and a HomeContoller to bootstrap the routing of the Angular SPA, similar to how Express might be used in NodeJS.&lt;/p&gt;

&lt;p&gt;As previously mentioned, in theory this project could be moved entirely out of .NET Core, and run solely on a NodeJS web server which could then communicate to the existing API back-end. In this scenario, I could see the Front-end Angular project being excluded from the Visual Studio solution, and possibly developed in a lighter-weight editor with better NodeJS support, like Sublime. The final trick was making sure that the port was predictable for the API container so that the Angular calls could reach, which I will discuss in the next section.&lt;/p&gt;

&lt;h4 id=&quot;the-docker-compose-files&quot;&gt;The Docker Compose files&lt;/h4&gt;
&lt;p&gt;The setup of the docker-compose.yml was pretty straight-forward based on the generated file with a few &lt;a href=&quot;https://docs.docker.com/compose/aspnet-mssql-compose/&quot;&gt;modifications&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;angular.web&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;angular.web&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./Angular&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;dockerfile&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Dockerfile&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;depends_on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;angular.api&lt;/span&gt;

  &lt;span class=&quot;s&quot;&gt;angular.api&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;angular.api&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;context&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;./Angular.API&lt;/span&gt;
      &lt;span class=&quot;na&quot;&gt;dockerfile&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Dockerfile&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;depends_on&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;db&lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;microsoft/mssql-server-linux:2017-latest&quot;&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;SA_PASSWORD&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;SuperSecretPassword&quot;&lt;/span&gt;
        &lt;span class=&quot;na&quot;&gt;ACCEPT_EULA&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;Y&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I combined all 3 containers into 1 file and added the depends_on sections, which helps ensure the containers are launched in the proper order.&lt;/p&gt;

&lt;p&gt;The other file of importance that is included is the docker-compose.override.yml file. This allows you to set some development overrides. Following the template that was auto-generated I ended up with:&lt;/p&gt;
&lt;div class=&quot;language-yaml highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;na&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
  &lt;span class=&quot;s&quot;&gt;angular.web&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ASPNETCORE_ENVIRONMENT=Development&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;80&quot;&lt;/span&gt;

  &lt;span class=&quot;s&quot;&gt;angular.api&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;environment&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ASPNETCORE_ENVIRONMENT=Development&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;4828:80&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Explicitly map this port because Angular.Web project expects it &lt;/span&gt;

  &lt;span class=&quot;na&quot;&gt;db&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;na&quot;&gt;ports&lt;/span&gt;&lt;span class=&quot;pi&quot;&gt;:&lt;/span&gt;
      &lt;span class=&quot;pi&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;1433:1433&lt;/span&gt; &lt;span class=&quot;c1&quot;&gt;# Explicitly map this port because SSMS expects it &lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here is where I was able to explicitly define both the API port, and the DB port so that it would be predictable and constant, not auto-assigned by Docker.&lt;/p&gt;

&lt;h4 id=&quot;sql-server-container&quot;&gt;SQL Server Container&lt;/h4&gt;
&lt;p&gt;Getting the initial SQL Server container up and running was pretty straight-forward thanks to the surprisingly comprehensive documentation and examples from both &lt;a href=&quot;https://docs.microsoft.com/en-us/sql/linux/quickstart-install-connect-docker&quot;&gt;Microsoft&lt;/a&gt; and Docker. However, in my initial attempt to get the container running I ran into a bug which I could not get around and &lt;a href=&quot;https://github.com/Microsoft/mssql-docker/issues/158&quot;&gt;finally assumed must have been in the Docker for Windows platform or SQL Container&lt;/a&gt;. It centered around the Memory requirement (4GB RAM) for the SQL Server container which I clearly met. I was able to figure out the problem thanks to &lt;a href=&quot;https://github.com/rabih-harb&quot;&gt;rabih&lt;/a&gt; who &lt;a href=&quot;https://github.com/Microsoft/mssql-docker/issues/20#issuecomment-296226637&quot;&gt;posted the code&lt;/a&gt; to print the stdout messages in the powershell console:&lt;/p&gt;
&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;docker&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;run&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;ACCEPT_EULA=Y&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-e&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;SA_PASSWORD=abc@123&quot;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;1433:1433&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stdin&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;stderr&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;microsoft/mssql-server-linux:2017-latest&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;After letting a few versions pass, I updated all my clients and all was well and running.&lt;/p&gt;

&lt;h3 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h3&gt;
&lt;p&gt;The next steps I would like to take with the projects in this solution are (in no particular order):&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;add full database support to the API so data can be pulled out of tables&lt;/li&gt;
  &lt;li&gt;continue to improve upon the front-end project by adding other NodeJS libraries and tools&lt;/li&gt;
  &lt;li&gt;look into swapping the Angular frontend for React frontend based on some feedback from a front-end team-member&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hope you learned something with me; till next time.&lt;/p&gt;</content><author><name>Jon Knopp</name></author><category term="Docker" /><category term="docker" /><category term="windows" /><category term="visual studio" /><summary type="html">After Part 1 where we created a build template in Packer for a Docker compatible image of Windows Server, capable of running containers, I was inspired by the West Wind Album Viewer sample project, and decided it was time to start developing a containerized app for the server to run. With Visual Studio 2017 and .NET Framework 4.7, there is native support for running containerized applications with Docker.</summary></entry><entry><title type="html">A Windows Docker Container Series (Part 1)</title><link href="https://jonknopp.com/docker/A-Windows-Docker-Container-Series-(Part-1)/" rel="alternate" type="text/html" title="A Windows Docker Container Series (Part 1)" /><published>2017-06-26T05:05:00-06:00</published><updated>2017-06-26T05:05:00-06:00</updated><id>https://jonknopp.com/docker/A-Windows-Docker-Container-Series-(Part-1)</id><content type="html" xml:base="https://jonknopp.com/docker/A-Windows-Docker-Container-Series-(Part-1)/">&lt;p&gt;In order to begin my journey into exploring Docker, I felt the need to incorporate as many of the &lt;a href=&quot;https://12factor.net&quot;&gt;12 Factor principles&lt;/a&gt; as I could into my development pipeline. I also wanted to have a clean place to get started on a Docker workflow, that was isolated from my normal .NET Development environment so as not to conflict, or pickup and unneeded dependencies. I had heard a lot about Hashicorp, and the tools they build for “provisioning, securing, connecting, and running any infrastructure for any application”. So, I decided I wanted to start there, with a fresh Packer Image that could be built, and reused from “scratch” as many times as I would need.&lt;/p&gt;

&lt;h4 id=&quot;an-introduction-to-packer&quot;&gt;An Introduction to Packer&lt;/h4&gt;
&lt;p&gt;Packer is an open source tool that was made to create machine images (“single static unit that contains a pre-configured operating system and installed software which is used to quickly create new running machines”) for multiple platforms from a single .json configuration file. It allows for faster deployments because provisioning time is eliminated, by allowing machines to pre-provisioned and configured, ahead of time, by Packer. This can also improve stability of deployment because Packer installs and configures all software for a machine when the image is built. If there are any issues with install scripts or configurations, they’ll be caught early, rather than several minutes after a machine is launched. Due to nature of how Packer creates machine images it allows for identical images to be created for multiple platforms (GCP, AWS, OpenStack, VMware, VirtualBox, HyperV, etc.), as transitioning between them can be nearly seamless.&lt;/p&gt;
&lt;h4 id=&quot;principle-10&quot;&gt;Principle #10&lt;/h4&gt;
&lt;p&gt;12 Factor principle #10 is on the “Dev/Prod parity”, and by keeping any images used identical between environments, we can take a large step towards reducing the gap that commonly exists. The. json which describes the machine images can also be used in a CI/CD scenario to have a blank machine created with each new build as a way to prevent configuration drift.&lt;/p&gt;

&lt;h3 id=&quot;why-does-it-matter&quot;&gt;Why does it matter?&lt;/h3&gt;
&lt;p&gt;I believe this can be a crucial step in reducing the “works on my machine but not on his/hers” issue that is common in development. I also feel that in the context of Agency business, it would be unreasonable to try and have someone maintain VMs for each client’s environment (especially at scale), in order to cater to their specific needs or requirements. Therefore, we end up with shared environments. With Packer, it would be much easier to maintain a few Packer files in the client’s repo that could be an exact environment, which matches prod, for any developer joining the project, no background knowledge required.&lt;/p&gt;

&lt;h3 id=&quot;walkthrough&quot;&gt;Walkthrough&lt;/h3&gt;
&lt;h4 id=&quot;windows-requirements&quot;&gt;Windows Requirements&lt;/h4&gt;
&lt;p&gt;To start off, I began learning about what would be required to run Docker Containers on Windows. Windows Containers are offered with two different base images, Windows Server Core and Nano Server. There are also 2 different mythologies supported for running containers “Windows Server Container” and “Hyper-V Container”. Windows Server Containers share the kernel between containers and the host, therefore mismatched versions are not supported. Hyper-V Containers utilize their own instance of the Windows kernel so you can miss-match the container host and container image versions. That lead me into determining which Windows version would support which of the different base-images, and container methodologies. Microsoft offer the following table under their &lt;a href=&quot;https://docs.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/system-requirements&quot;&gt;“Windows Container Requirements” documentation&lt;/a&gt;:&lt;/p&gt;

&lt;table&gt;
  &lt;thead&gt;
    &lt;tr&gt;
      &lt;th&gt;Host Operating System&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Windows Server Container&lt;/th&gt;
      &lt;th style=&quot;text-align: center&quot;&gt;Hyper-V Container&lt;/th&gt;
    &lt;/tr&gt;
  &lt;/thead&gt;
  &lt;tbody&gt;
    &lt;tr&gt;
      &lt;td&gt;Windows Server 2016 (Standard or Datacenter)&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Server Core / Nano Server&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Server Core / Nano Server&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Nano Server&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Nano Server&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Server Core / Nano Server&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
      &lt;td&gt;Windows 10 Pro / Enterprise&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Not Available&lt;/td&gt;
      &lt;td style=&quot;text-align: center&quot;&gt;Server Core / Nano Server&lt;/td&gt;
    &lt;/tr&gt;
  &lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;Based on this chart I felt it would be best use a workflow centered around Windows Server 2016, as it had the broadest support, covering all variations, of running Docker Containers on Windows.
After determining I wanted to use Windows Server 2016 as my staring point I began to browse GitHub to see if I could find any existing Windows Server 2016 Packer templates.&lt;/p&gt;

&lt;h4 id=&quot;packer-template&quot;&gt;Packer Template&lt;/h4&gt;
&lt;p&gt;&lt;a href=&quot;https://www.packer.io/docs/builders/hyperv-iso.html&quot;&gt;Packer.io&lt;/a&gt; had the below template for getting started with Hyper-V (which is what comes by default in Windows 10 Enterprise, so that’s what I went with):&lt;/p&gt;

&lt;div class=&quot;language-javascript highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;builders&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;vm_name&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;windows2012r2&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;hyperv-iso&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;disk_size&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;61440&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;floppy_files&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[],&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;secondary_iso_images&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./windows/windows-2012R2-serverdatacenter-amd64/answer.iso&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;http_directory&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./windows/common/http/&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;boot_wait&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;0s&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;boot_command&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;a&amp;lt;wait&amp;gt;a&amp;lt;wait&amp;gt;a&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;iso_url&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;http://download.microsoft.com/download/6/2/A/62A76ABB-9990-4EFC-A4FE-C7D698DAEB96/9600.16384.WINBLUE_RTM.130821-1623_X64FRE_SERVER_EVAL_EN-US-IRM_SSS_X64FREE_EN-US_DV5.ISO&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;iso_checksum_type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;md5&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;iso_checksum&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;458ff91f8abc21b75cb544744bf92e6a&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;communicator&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;winrm&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;winrm_username&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;vagrant&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;winrm_password&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;vagrant&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;winrm_timeout&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;4h&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;shutdown_command&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;f:&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;run-sysprep.cmd&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;  
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;ram_size&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4096&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;cpu&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;4&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;generation&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;switch_name&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;LAN&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;enable_secure_boot&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;kc&quot;&gt;true&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;provisioners&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;powershell&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;elevated_user&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;vagrant&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;elevated_password&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;vagrant&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;scripts&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./windows/common/install-7zip.ps1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./windows/common/install-chef.ps1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./windows/common/compile-dotnet-assemblies.ps1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./windows/common/cleanup.ps1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./windows/common/ultradefrag.ps1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;./windows/common/sdelete.ps1&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
      &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;],&lt;/span&gt;
  &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;post-processors&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;vagrant&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;keep_input_artifact&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt;
      &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;output&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;_windows-2012r2_chef.box&lt;/span&gt;&lt;span class=&quot;dl&quot;&gt;&quot;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;]&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Also, want to give credit to the most helpful public Github repo I came across from Stefan Scherer: &lt;a href=&quot;https://github.com/StefanScherer/packer-windows&quot;&gt;Packer Windows&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since this file is the main configuration file, I will do my best to explain what it’s doing.&lt;/p&gt;

&lt;p&gt;The first section defines a builder object. Builders are how you write definitions for creating different machines, and for generating an image for plaforms such as Azure, Docker, EC2, VMware, VirtualBox, and of course, Hyper-V.&lt;/p&gt;

&lt;p&gt;Within the builder, there are many parameters defined, without going into them all indivdually, they provide Packer with the information needed to create a machine image via the command-line on the specified platform. In this case we are creating a Windows Server 2016 image so we need to provide Packer all the variables need to perform a &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/ee251019%28v=bts.10%29.aspx&quot;&gt;“silent install”&lt;/a&gt; of the OS.&lt;/p&gt;

&lt;p&gt;The next section defines a provisioner object. According to Packer documentation, “Provisioners use builtin, and third-party software, to install, and configure, the machine image after booting to prepare the system for use”. Commom uses are:&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;installing packages (zip utility, windows features)&lt;/li&gt;
  &lt;li&gt;patching the kernel (installing Windows updates&lt;/li&gt;
  &lt;li&gt;creating users (creating the default ‘vagrant’ user)&lt;/li&gt;
  &lt;li&gt;downloading application code (Docker)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The final section defines an optional post-processor object. Post-processers are used to do things with your image after they have been prepeared. In my case, like the example from Packer above also, I chose to use the &lt;a href=&quot;https://www.packer.io/docs/post-processors/vagrant.html&quot;&gt;Vagrant post-processor&lt;/a&gt;, which prepares the Hyper-V VM for use with another Hashicorp tool &lt;a href=&quot;https://www.vagrantup.com&quot;&gt;Vagrant&lt;/a&gt; in conjunction with Hyper-V.&lt;/p&gt;

&lt;h4 id=&quot;running-packer&quot;&gt;Running Packer&lt;/h4&gt;
&lt;p&gt;The brilliance of Packer is in it’s simplicity. Once the configuration is complete, all one has to do to create the machine image is the following command from PowerShell using elevated privileges:&lt;/p&gt;
&lt;div class=&quot;language-powershell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;n&quot;&gt;packer&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;build&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nt&quot;&gt;-var&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;'hyperv_switchname=Ethernet'&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nx&quot;&gt;\windows_2016_docker.json&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;I specified as a variable my exisitng Hyper-V switch, so that when the machine boots during the install, it is able to connect to the internet for Windows Updates (optional), and various other tasks in the provisioning step.&lt;/p&gt;

&lt;h3 id=&quot;next-steps&quot;&gt;Next Steps&lt;/h3&gt;
&lt;p&gt;The next steps I would like to take with packer are (in no particular order):&lt;/p&gt;
&lt;ul&gt;
  &lt;li&gt;continuing to add provisiong scripts which add my presonal preferences to the Windows Server machine.&lt;/li&gt;
  &lt;li&gt;create new builders for other plaforms so I can ensure my machine image is able to run anywhere&lt;/li&gt;
  &lt;li&gt;use my &lt;a href=&quot;https://cloud.google.com/solutions/automated-build-images-with-jenkins-kubernetes&quot;&gt;Packer Image Builds in a full CI/CD workflow&lt;/a&gt; with Jenkins and Kubernetes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Hope you learned something with me; till next time.&lt;/p&gt;</content><author><name>Jon Knopp</name></author><category term="Docker" /><category term="docker" /><category term="windows" /><category term="packer" /><summary type="html">In order to begin my journey into exploring Docker, I felt the need to incorporate as many of the 12 Factor principles as I could into my development pipeline. I also wanted to have a clean place to get started on a Docker workflow, that was isolated from my normal .NET Development environment so as not to conflict, or pickup and unneeded dependencies. I had heard a lot about Hashicorp, and the tools they build for “provisioning, securing, connecting, and running any infrastructure for any application”. So, I decided I wanted to start there, with a fresh Packer Image that could be built, and reused from “scratch” as many times as I would need.</summary></entry></feed>