<?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: Erik Lindblom</title>
    <description>The latest articles on DEV Community by Erik Lindblom (@baens).</description>
    <link>https://dev.to/baens</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%2F52901%2Face4c867-6fab-4c55-8804-b102da5bfa65.jpeg</url>
      <title>DEV Community: Erik Lindblom</title>
      <link>https://dev.to/baens</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/baens"/>
    <language>en</language>
    <item>
      <title>Preventing your Kubernetes volume from being deleted in GKE</title>
      <dc:creator>Erik Lindblom</dc:creator>
      <pubDate>Tue, 30 Jun 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/baens/preventing-your-kubernetes-volume-from-being-deleted-in-gke-5d9l</link>
      <guid>https://dev.to/baens/preventing-your-kubernetes-volume-from-being-deleted-in-gke-5d9l</guid>
      <description>&lt;h1&gt;
  
  
  The story
&lt;/h1&gt;

&lt;p&gt;This one caught off guard. I have this Kubernetes cluster I managed, and well, one day I was doing my thing. And I noticed that my laptop was low on resources, so I decided to clean things up. Cleared out a few namespaces and everything was good to go. Well, not 3 seconds later, someone pings on a chat channel that their dev environment is gone. Well...crap. I double-check my &lt;code&gt;kubectl&lt;/code&gt; context, and yup, sure enough. I was not connected to my local instance, I was connected to the dev Kubernetes cluster. Oops!&lt;/p&gt;

&lt;p&gt;Thankfully this was only dev, and not production or anywhere else important. But it still stood I blew up the cluster, and needed to rebuild it, and quickly. This post isn't how I brought that cluster back online (spoiler: we have tools and pipelines to do that quickly), but how I figured out preventing this from happening in the future.&lt;/p&gt;

&lt;h1&gt;
  
  
  What are PVCs
&lt;/h1&gt;

&lt;p&gt;Let's make sure we are on the same page. If you don't know. Persistent volume claims (PVC) are a way for you to get permanent disk storage in your Kubernetes cluster. This means if your pod dies, or is deleted, you can have your data persist. This is all fine and dandy but by default. Those PVCs are a &lt;a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/namespaces/#not-all-objects-are-in-a-namespace"&gt;namespaced resource&lt;/a&gt;. Which means if you delete the namespace. That resource is also deleted.&lt;/p&gt;

&lt;h1&gt;
  
  
  Using persistent disks in GKE
&lt;/h1&gt;

&lt;p&gt;To prevent your data from getting lost if the namespace is deleted. You need to attach that data to a disk that lives outside of Kubernetes control. To do this, we will use a disk created in Google cloud, and attach to that disk inside our Kubernetes environment. This is &lt;a href="https://cloud.google.com/kubernetes-engine/docs/concepts/persistent-volumes"&gt;documented in GKE&lt;/a&gt; but let me give you the easy steps of getting there:&lt;/p&gt;

&lt;p&gt;First, let's create the disk:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcloud compute disks create my-disk --type=pd-ssd --size=1G
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, let's attach to that disk in a pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: PersistentVolume
metadata:
  name: demo
spec:
  capacity:
    storage: 1G
  accessModes:
    - ReadWriteOnce
  claimRef:
    namespace: default
    name: demo
  gcePersistentDisk:
    pdName: my-disk
    fsType: ext4
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: demo
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1G
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Lots of stuff right? Some import bits are that we supply both the &lt;code&gt;PersistentVolume&lt;/code&gt; and the &lt;code&gt;PersistentVolumeClaim&lt;/code&gt;. Usually, we only had the claim itself. On the volume, the &lt;code&gt;gcePersistentDisk&lt;/code&gt; identities the name of the disk to attach to, and fail if it not found. Also, the &lt;code&gt;claimRef&lt;/code&gt; needs to match up with both the namespace and the name for this to be bound correctly. Also, be careful that the storage also lines up correctly, otherwise again, things won't be bound.&lt;/p&gt;

&lt;h1&gt;
  
  
  Migrate to use that disk
&lt;/h1&gt;

&lt;p&gt;So, creating a disk is rather straight forward, but what if you already have a disk and want to migrate over to this? We can do that. All PVCs in GKE already have a disk attached to them. They are just managed outside of the cluster itself. So here is the general workflow you will need to go through to migrate over to something more permanent:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scale down your pods&lt;/li&gt;
&lt;li&gt;Take a snapshot of your current disk&lt;/li&gt;
&lt;li&gt;Delete your current deployment&lt;/li&gt;
&lt;li&gt;Create a disk from the snapshot&lt;/li&gt;
&lt;li&gt;Deploy again with the PVC attacked to the disk&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  Step: Scaling down the pods
&lt;/h1&gt;

&lt;p&gt;To ensure that all the data is done being written to the disks, and nothing changes the data mid-flight. It is a good idea to make sure all pods that are using the disks are scaled down to 0. If you are using a deployment, this is as easy as &lt;code&gt;kubectl scale --replicas=0 deployment/my-stuff&lt;/code&gt;. Then verify that all the pods are gone before proceeding on to the next step.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step: Snapshotting your current disk
&lt;/h1&gt;

&lt;p&gt;To get us to a new disk, we need to go through and create a snapshot of the data you currently have, to seed the permanent disk. Whats need is that we can actually script this next part out. Here is what this script would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Capture properties of disk
VOLUME_NAME=$(kubectl get pvc my-pvc -o=jsonpath='{.spec.volumeName}')
DISK_NAME=$(gcloud compute disks list --filter="name~''$VOLUME_NAME''" --format="value(name)")
DISK_ZONE=$(gcloud compute disks list --filter="name~''$VOLUME_NAME''" --format="value(zone)")

gcloud compute disk snapshot --zone $DISK_ZONE --snapshot-names my-snapshot $DISK_NAME
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;First, we had to capture data from the PVC. In this example, &lt;code&gt;mv-pvc&lt;/code&gt; would be the name of the PVC you create in your cluster. We capture the volume name which is the name of the disk created outside of the cluster.&lt;/p&gt;

&lt;p&gt;Next, we need to capture some information about the disk itself. We need to know the full disk name, along with which zone it was created in.&lt;/p&gt;

&lt;p&gt;From there, we then have all the information we need to create our snapshot &lt;code&gt;my-snapshot&lt;/code&gt; (all these names can be tweaked, and are given as examples).&lt;/p&gt;

&lt;h1&gt;
  
  
  Step: Deleting your deployment
&lt;/h1&gt;

&lt;p&gt;Next, let's go ahead and delete your deployment. If you want a simple one-liner, you can use &lt;code&gt;kubectl&lt;/code&gt; to delete everything: &lt;code&gt;kubectl delete all,pvc,pv --all-namespaces -l app=my-app&lt;/code&gt;. The label (&lt;code&gt;-l&lt;/code&gt;) assumes you have some kind of annotation attached to your resources.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step: Creating the disk
&lt;/h1&gt;

&lt;p&gt;Now that we have everything cleaned up, let's create the new disk.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcloud compute disks create my-disk --size=1G --source-snapshot=my-snapshot --type=pd-ssd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Fairly straight forward. This will create the disk with a 1G limit. We use the SSD disk type because we are under 100GB for this example. But tweak it for your needs.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step: Deploying to the attached disk
&lt;/h1&gt;

&lt;p&gt;Now that we have the disk ready, we need to redeploy our service back into Kubernetes. But this time, we need to ensure that your PVC attaches to the disk. We will use a manifest like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apiVersion: v1
kind: PersistentVolume
metadata:
  name: demo
spec:
  capacity:
    storage: 1G
  accessModes:
    - ReadWriteOnce
  claimRef:
    namespace: default
    name: demo
  gcePersistentDisk:
    pdName: my-disk
    fsType: ext4
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: demo
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1G
---
kind: Deployment
apiVersion: apps/v1
metadata:
  name: demo
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    volumes:
      - name: storage
        persistentVolumeClaim:
          claimName: demo
    spec:
      containers:
        - name: task-pv-container
          image: nginx
          ports:
            - containerPort: 80
            name: "http-server"
          volumeMounts:
            - mountPath: "/usr/share/nginx/html"
            name: task-pv-storage
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If all goes well, all your data is still present and you have no migrated over to a more permanent disk.&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>gcp</category>
      <category>gke</category>
    </item>
    <item>
      <title>Terraform, Google Cloud, and Kubernetes working together</title>
      <dc:creator>Erik Lindblom</dc:creator>
      <pubDate>Sun, 07 Jun 2020 00:00:00 +0000</pubDate>
      <link>https://dev.to/baens/terraform-google-cloud-and-kubernetes-working-together-1n50</link>
      <guid>https://dev.to/baens/terraform-google-cloud-and-kubernetes-working-together-1n50</guid>
      <description>&lt;p&gt;Here is the situation: I want a secret (let's say a database password or any Kubernetes resource) stored inside a Kubernetes secret. The infrastructure is controlled by Terraform. So, how do I go about to keep those two things in sync?&lt;/p&gt;

&lt;p&gt;Well, recently I found out a neat pattern! You can connect Terraform with both GCP infrastructure, and Kubernetes at the same time, and you can keep them in sync! How do you say? Well, let me show you!&lt;/p&gt;

&lt;p&gt;Let's look at the full-blown example and then we will break the interesting bits down:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;provider "google" {
}

data "google_client_config" "default" {
}

provider "kubernetes" {
  load_config_file = false
  host             = "https://${google_container_cluster.primary.endpoint}"
  token            = data.google_client_config.default.access_token
  cluster_ca_certificate = base64decode(
    google_container_cluster.primary.master_auth[0].cluster_ca_certificate
  )
}

resource "kubernetes_namespace" "test" {
  metadata {
    name = "test"
  }

  depends_on = [google_container_node_pool.primary]
}

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Ok, ok. This isn't a full-blown example, but these are the most important pieces. The full example can be found in my &lt;a href="https://github.com/baens/code-examples-blog.baens.net/tree/terraform-kubernetes-secret"&gt;example repository here&lt;/a&gt;. Here I am just highlighting the pieces you probably already want and need.&lt;/p&gt;

&lt;p&gt;The first big piece you will need is the &lt;a href="https://registry.terraform.io/providers/hashicorp/google/3.24.0/docs/data-sources/datasource_client_config"&gt;&lt;code&gt;google_client_config&lt;/code&gt;&lt;/a&gt;. This piece is the one that led me down this road in the first place. This gives information back to Terraform on how to access the Google API and how to use other pieces. The most important piece here is the access token. This is a short-lived token that will be used to communicate with the cluster with whatever privilege the gcloud command (or Terraform provider context) has.&lt;/p&gt;

&lt;p&gt;As you may notice, the &lt;code&gt;google_container_cluster&lt;/code&gt; gives us the other pieces. It gives us the host, along with the CA certificate of the host. This then gives you full access to the Kubernetes instance and allows you to start managing the instance with Kubernetes!&lt;/p&gt;

&lt;p&gt;Now the next bit that may trip people up is the &lt;code&gt;depends_on&lt;/code&gt;. Because the provider doesn't naturally give you dependencies. Terraform can't figure out the dependency graph on its own, so it needs some help. We specifically target the node pool because we want actual node workers in kubernetes for certain things to work (i.e. namespace is a good example that needs a worker node to work fully). If you don't have this, destroying and or other massive changes might leave you in a stuck state.&lt;/p&gt;

&lt;p&gt;Now that we've tied things together using a basic namespace. Let's see how we would tie a secret. In our case, this will be the password to the database user. This would look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;resource "random_password" "user" {
  length = 16
}

resource "google_sql_user" "users" {
  name     = "user"
  instance = google_sql_database_instance.instance.name
  password = random_password.user.result
}

resource "kubernetes_secret" "user" {
  metadata {
    name      = "user-password"
    namespace = kubernetes_namespace.test.metadata[0].name
  }

  data = {
    password = random_password.user.result
  }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We use Terraform to generate the password, the link the two other resources together. In this case, we create a SQL user and the secret to store that same password for a pod to use to connect to the database.&lt;/p&gt;

&lt;p&gt;The trickiest part of all of this is to ensure that the dependency graph that Terraform generates is accurate. So using &lt;code&gt;depends_on&lt;/code&gt; and other things may need to be used more often.&lt;/p&gt;

</description>
      <category>terraform</category>
      <category>gcp</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Step by Step: A simple Node.js, Docker, and Kubernetes setup</title>
      <dc:creator>Erik Lindblom</dc:creator>
      <pubDate>Sat, 16 Nov 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/baens/step-by-step-a-simple-node-js-docker-and-kubernetes-setup-3h8o</link>
      <guid>https://dev.to/baens/step-by-step-a-simple-node-js-docker-and-kubernetes-setup-3h8o</guid>
      <description>&lt;p&gt;I've now been playing with Node.js, Docker, and Kubernetes for quite some time. And it just so happen that recently someone needed a good introduction to Node.js, Docker, and Kubernetes. However, after searching online I couldn't find one that just had a few simple things to walk through. So, here this is. Hopefully this blog post will demonstrate how to create a simple Node.js, create a Docker container, demonstrate it running, then deploy that Docker container to a local Kubernetes setup. There will be light touches on what exactly all of those parts are and hopefully give you a starting point to start exploring these technology stacks.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 0: Prerequisites
&lt;/h1&gt;

&lt;p&gt;I am going to assume a few things in this blog post. First, you have &lt;a href="https://nodejs.org/"&gt;Node.js&lt;/a&gt; installed. I prefer to use &lt;a href="https://github.com/nvm-sh/nvm"&gt;nvm&lt;/a&gt; as my manager of my node instance, but there are several out there that can do the trick. For this blog post, I will be using the latest LTS Dubnium release 10.16.3. I will also be using &lt;a href="https://yarnpkg.com/"&gt;yarn&lt;/a&gt; as the Node.js package manager.&lt;/p&gt;

&lt;p&gt;Next, we will need &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; installed. If you are using Mac or Windows, go ahead and get the wonderful &lt;a href="https://www.docker.com/products/docker-desktop"&gt;Docker for Mac/Windows&lt;/a&gt; tools. This will give you a wonderful set of tools to use Docker on those platforms. For Linux, go aheads and get a &lt;a href="https://docs.docker.com/v17.12/install/#server"&gt;Docker CE&lt;/a&gt; from what ever distro package you have. For this blog post, I will be running Docker for Mac 2.1.3.0. I will also verify that it works on Linux, but sadly don't have a way to verify Windows at this time. There isn't anything too complicated here so I have some confidence that it should work across platforms fairly easily.&lt;/p&gt;

&lt;p&gt;Next, we will need a Kubernetes instance running locally. For Mac and Windows, that is built into the &lt;a href="https://docs.docker.com/docker-for-mac/#kubernetes"&gt;Docker for Desktop&lt;/a&gt; tool. For Linux, I recommend &lt;a href="https://kubernetes.io/docs/tasks/tools/install-minikube/"&gt;Minikube&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That should be all of the base tools you will need. Hopefully those are all fairly easy to install, but if you run into issues, please reach out to me and I'll attempt to help and add notes to this blog post for future visitors.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1: A basic node server running
&lt;/h1&gt;

&lt;p&gt;First thing first, let's setup our environment with a very basic Node.js &lt;a href="https://expressjs.com"&gt;Express&lt;/a&gt; server and get it running. Get to a blank directory and run the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; yarn init &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, let's get our &lt;code&gt;Express&lt;/code&gt; library. We do that by running the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; yarn add express@4.17.1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;&lt;em&gt;Rant&lt;/em&gt;&lt;/strong&gt;: Now, if you are familiar with the Node.js ecosystem you may find it very odd that I added a specific version of the express library. First, you should definitely try and lock your packages down to as specific version as you can. Personally, I've been bitten far too many times by drifting dependencies. Yes, the lock files help this, but it still happens from time to time. So try and lock things down to as specific as possible. I hope you will thank me later, and I'm sad that the Node community uses fuzzy versions far too often in my opinion.&lt;/p&gt;

&lt;p&gt;This should install the &lt;code&gt;Express&lt;/code&gt; library and create a &lt;code&gt;yarn.lock&lt;/code&gt; file and a &lt;code&gt;node_modules&lt;/code&gt; folder with all the files needed for that library. Now that we have &lt;code&gt;Express&lt;/code&gt;, let's create a very simple server. Here is what you want in the file &lt;code&gt;index.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Hello World&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Running server&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's go ahead and run this file by running the following in a command prompt: &lt;code&gt;node index.js&lt;/code&gt;. You should get the &lt;code&gt;Running server&lt;/code&gt; output on the console and then you can visit &lt;a href="http://localhost:8080"&gt;http://localhost:8080&lt;/a&gt; and see the &lt;code&gt;Hello World&lt;/code&gt; text in the web browser. If you do, congratulations! We have a very simple web server up and running. If not, double check that you have the package installed correctly, and that your &lt;code&gt;index.js&lt;/code&gt; is in the same folder as the &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;node_modules&lt;/code&gt; folder. Please reach out if you need help getting past this step so I can help troubleshooting steps.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 2: Dockerize
&lt;/h1&gt;

&lt;p&gt;Now that we have some working code, let's go ahead and get this application stuffed into a Docker container. Create a file named &lt;code&gt;Dockerfile&lt;/code&gt; and put this inside of it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:10.16.3 as builder&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /build&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;yarn &lt;span class="nb"&gt;install&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;yarn &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--production&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:10.16.3-slim&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /build/node_modules ./node_modules/&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /build/index.js .&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; node index.js&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Let's go through this line by line to understand what we are doing:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 1:&lt;/em&gt; Very first thing you do in a Dockerfile is define where the starting point is. For us, we are going to use the Node with our locked in version. Now, something you may not be familiar with is the &lt;code&gt;as builder&lt;/code&gt;. We are going to use what is called a &lt;a href="https://docs.docker.com/develop/develop-images/multistage-build/"&gt;multi-stage build&lt;/a&gt;. This is slightly overkill for our example, but this is a framework for future work. We are going to use a builder that will build up our application. Then we will copy over the smallest amount of bits we absolutely need for a production system. This way we have the smallest image we need to ship into production. Also from a security perspective, we are shipping the smallest amount of thing so our foot print is as small as possible.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 3:&lt;/em&gt; The &lt;a href="https://docs.docker.com/engine/reference/builder/#workdir"&gt;WORKDIR&lt;/a&gt; command sets our default working from and also sets where we are currently working from. We are going to use a folder at the root called &lt;code&gt;build&lt;/code&gt; and work from there&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 4:&lt;/em&gt; First we are copying over everything into our Docker container with a neat little trick of &lt;code&gt;COPY . .&lt;/code&gt;. Now, this may look funny so let me explain what kind of magic this is doing. Remember that we are asking the Docker system to copy things into the Docker environment. So the first parameter in &lt;code&gt;COPY&lt;/code&gt; is referencing from the filesystem relative to the &lt;code&gt;Dockerfile&lt;/code&gt;. The second parameter is referencing in relation to where in the Docker container it should put those files. For us, we are asking to copy everything from our project, into the Docker container. It's a neat trick I employ instead of trying to copy different folders. If I need to exclude things, you will use the &lt;a href="https://docs.docker.com/engine/reference/builder/#dockerignore-file"&gt;.dockerignore&lt;/a&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 5-6:&lt;/em&gt; Now, this looks VERY odd, but just hang in there with me. First we use &lt;code&gt;yarn install&lt;/code&gt; to get all of the dependencies. While, yes, the very next line we do &lt;code&gt;yarn install --production&lt;/code&gt;, I do this for a good reason. More likely then not, you will want a build step to do something. Either packing, compiling, transpiling, take your pick. You can add any step in between those two &lt;code&gt;yarn install&lt;/code&gt; commands to get the right build system setup that you need.&lt;/p&gt;

&lt;p&gt;Now that we have a docker image, let's just go through and test this docker image and make sure things work just like they did in the last step. First, let's build the docker image by running &lt;code&gt;docker build . -t myimage&lt;/code&gt;. The &lt;code&gt;-t myimage&lt;/code&gt; tags the image with a name we can easily use.&lt;/p&gt;

&lt;p&gt;To run the image you just built run &lt;code&gt;docker run --rm -it -p 8080:8080 myimage&lt;/code&gt;. You should be able to hit &lt;a href="http://localhost8080"&gt;http://localhost:8080&lt;/a&gt; and get the same &lt;code&gt;Hello World&lt;/code&gt; text like you did in the last time. hit &lt;code&gt;ctrl+c&lt;/code&gt; to stop the image.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 3: Pushing a docker image and prep work for kubernetes
&lt;/h1&gt;

&lt;p&gt;In this tutorial, I am going to assume you have a kubernetes instance up and running somewhere. If you don't, you can either use &lt;a href="https://www.docker.com/blog/kubernetes-is-now-available-in-docker-desktop-stable-channel/"&gt;Docker for Desktop&lt;/a&gt; which has Kubernetes built in for both Mac and Windows. Or, you can use &lt;a href="https://github.com/kubernetes/minikube"&gt;minikube&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;No matter where you have it running. This tutorial will assume you have &lt;code&gt;kubectl&lt;/code&gt; pointed to a running Kubernetes instance and that you also have a registry you can upload your docker image.&lt;/p&gt;

&lt;p&gt;Let me actually go into detail a little bit about that last thing. We need to push the Docker image to a registry for your Kubernetes instance to pull down. Now, there a wide range of place you can do that. And that require a wide variety of different methods to do it. I am going to assume that you can &lt;code&gt;docker push&lt;/code&gt; some kind of image somewhere and that is accessible to your Kubernetes cluster. If you and running the Docker for Desktop tool, a &lt;code&gt;docker build&lt;/code&gt; will suffice. If you are running Minikube, you will need to &lt;a href="https://minikube.sigs.k8s.io/docs/tasks/docker_daemon/"&gt;reuse the Docker daemon&lt;/a&gt;. If you are running a cluster in the cloud somewhere, you will have to make sure that &lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/"&gt;Kubernetes is setup to pull from that registry&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 4: Deploying that image to Kubernetes
&lt;/h1&gt;

&lt;p&gt;With your image now ready to deploy, lets go through what that would require. For this tutorial we are going to create a &lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/"&gt;deployment&lt;/a&gt; and a &lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/"&gt;service&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A deployment is a Kubernetes object that defines how to create "&lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/pod/"&gt;pods&lt;/a&gt;". A pod is a single (but can be multiple) runner Docker instance. A deployment controls how many pods are currently running and has all of the logic built into making sure there are enough pods to satisfy your requirements. It also helps control roll outs as you update your image. This means that as you roll out a new image, it will bring a new pod up, make sure the pod is running, and then kill off old pods in a controlled manner. Deployments are usually your bread and butter, but they aren't the only objects that control pods. There are a &lt;a href="https://kubernetes.io/docs/concepts/architecture/controller/"&gt;few different types&lt;/a&gt; of controllers out there but this tutorial will only be focused on the deployment variety.&lt;/p&gt;

&lt;p&gt;So, if a deployment controls whats running inside of Kubernetes, how do we expose that pod to network traffic? Like maybe public internet traffic? That is where services come in. A service is a Kubernetes object that controls how network connections are made to the pods. A service defines which ports are open and are connected, and whether the pods should be exposed internally to the Kubernetes instance or externally. Services can also do &lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/#loadbalancer"&gt;load balancing&lt;/a&gt; if you desire.&lt;/p&gt;

&lt;p&gt;Now, while this glossed over a lot of details, I think this should make you dangerous enough to start with. Let's look at how a deployment and service object are created and deployed to Kubernetes now. Let's take a look at this file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;apps/v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deployment&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app&lt;/span&gt;
  &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;replicas&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;matchLabels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app&lt;/span&gt;
  &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;labels&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app&lt;/span&gt;
    &lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app&lt;/span&gt;
        &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;myimage&lt;/span&gt;
        &lt;span class="na"&gt;imagePullPolicy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Never&lt;/span&gt;
        &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;containerPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-service&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-app&lt;/span&gt;
  &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;LoadBalancer&lt;/span&gt;
  &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;protocol&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;TCP&lt;/span&gt;
      &lt;span class="na"&gt;port&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8080&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Holy crap batman thats alot! Let's walk through what all of this means.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 1 &amp;amp; 24&lt;/em&gt;: For this example I put both objects inside of one file. Not always a normal thing todo, but its an option. The &lt;code&gt;---&lt;/code&gt; is a YAML file separator for multiple YAML objects inside of a file. Just want to point this out first if you see these files separated in the wild. Thats fine, I just wanted to give you one file to play with instead of multiple.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 2, 3, 25 &amp;amp; 26&lt;/em&gt;: This describe the type of Kubernetes object. There are two parts to this. The &lt;code&gt;apiVersion&lt;/code&gt;, and the &lt;code&gt;kind&lt;/code&gt; of object. These set of properties let's Kubernetes define a whole host of options and let's them version out behavior for certain objects. You can find which objects are support by running &lt;code&gt;kubectl api-resources&lt;/code&gt; and the versions of those with &lt;code&gt;kubectl api-versions&lt;/code&gt;. The resources list which API group is used, which you cross-reference to which version you should use. If the resource is listed blank, its part of "core" which is usually just &lt;code&gt;v1&lt;/code&gt;. You usually don't fiddle with this much, and just copy from project to project. But its better to be aware of why this is here then just blindly copying it.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 4 - 7&lt;/em&gt;: This section describes the metadata for the deployment. Metadata is just that, information about the object. For a deployment there are two main parts, a &lt;code&gt;name&lt;/code&gt; which is exactly that, and is required. Then some kind of &lt;code&gt;label&lt;/code&gt;. The label is important because this gives you the ability to "select" this deployment depending on what kind of values you give the object. This will become important later on in our service.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 8&lt;/em&gt;: This starts the meat of the deployment object, the &lt;code&gt;spec&lt;/code&gt; or specification of what you want to deploy.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 9&lt;/em&gt;: The &lt;code&gt;replicas&lt;/code&gt; is the number of instances you want running.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 10 - 12&lt;/em&gt;: This section describes what pods the deployment controls. Usually this means you create a selector that has the same matching labels as your &lt;code&gt;template&lt;/code&gt; section. I personally haven't come across a case where this didn't match up with what I had in the &lt;code&gt;template&lt;/code&gt; section, but I'm sure there are cases out there.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 13&lt;/em&gt;: This is the start of the &lt;code&gt;template&lt;/code&gt; section. The template section will describe what each pod will have. This includes the image of the container, along with any environment variables, files, etc that are needed to run that pod.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 14 - 16&lt;/em&gt;: This section contains the &lt;code&gt;metadata&lt;/code&gt; for each pod that is run. Again, usually this just contains the a label that has information for your selector in the above section.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 17&lt;/em&gt;: This defines the &lt;code&gt;spec&lt;/code&gt; for a pod. In this example we will have only 1 container, but this is the section we would add information for an &lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/init-containers/"&gt;&lt;code&gt;initContainer&lt;/code&gt;&lt;/a&gt; or &lt;a href="https://kubernetes.io/docs/concepts/workloads/pods/pod-overview/#how-pods-manage-multiple-containers"&gt;side car containers&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 18 - 23&lt;/em&gt;: This is the meat of the pod. We define a &lt;code&gt;name&lt;/code&gt;, a &lt;code&gt;image&lt;/code&gt;, and the &lt;code&gt;ports&lt;/code&gt; that are exposed. The name can be whatever you want, it doesn't necessarily have to match the deployment name, but usually does for making life easier later. The &lt;code&gt;image&lt;/code&gt; is the location of the docker image. In this example I am assuming that you are using the Docker for Desktop tool, which means we can give it the same name as the last step (&lt;code&gt;myimage&lt;/code&gt;). I also added a &lt;code&gt;imagePullPolicy&lt;/code&gt; because the Kubernetes instance inside of that tool should not try and reach out to the internet for this image. I would recommend &lt;a href="https://kubernetes.io/docs/concepts/containers/images/#updating-images"&gt;reading up on which image pull policy&lt;/a&gt; is right for your situation. We list the ports that are exposed next. This isn't completely necessarily but usually added for documentation proposes.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 29&lt;/em&gt;: This section defines our service and how it operates. Let's dig into this section now.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 30 - 31&lt;/em&gt;: This defines what pods should be exposed through this service. This usually matches very closely to what the deployment had in its selector as well.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 32&lt;/em&gt;: Since we want to expose this service we want to put a &lt;code&gt;type&lt;/code&gt; on it. There are a &lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types"&gt;couple of types&lt;/a&gt;, and the one we are interested in is the &lt;code&gt;LoadBalancer&lt;/code&gt;. This is because we want to expose this service outside of Kubernetes, and that requires a load balancer for that.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Line 33 - 36&lt;/em&gt;: This defines the ports that are going to be exposed from this service. For our example, we are going to take the pods port 8080 (&lt;code&gt;targetPort&lt;/code&gt;) and expose it to the outside world on that same port 8080 (&lt;code&gt;port&lt;/code&gt;). We could have exposed it on port 80 if we wanted too. But for this instance, we just went for the easy route of aligning those numbers up.&lt;/p&gt;

&lt;p&gt;Phew, that is a lot. So what should I do with all of this now? Well, let's deploy it. To do that we would run &lt;code&gt;kubectl apply -f deploy.yaml&lt;/code&gt;. This of courses assumes that all of the above is in a file called &lt;code&gt;deploy.yaml&lt;/code&gt;. Kubectl would then submit that file to Kubernetes and the magic starts to happen on creating the pods. To see your pods up and running we would run &lt;code&gt;kubectl get pods&lt;/code&gt; and &lt;em&gt;hopefully&lt;/em&gt; you would see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; kubectl get pods
NAME                    READY   STATUS        RESTARTS   AGE
my-app-bb697dc4-q6vl7   1/1     Running       0          14s
my-app-bb697dc4-qpjgf   1/1     Running       0          14s
my-app-bb697dc4-vsxcv   1/1     Running       0          14s
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see, you see the &lt;code&gt;name&lt;/code&gt; attribute come through. Along with a deployment number (&lt;code&gt;bb697dc4&lt;/code&gt; in this example) and a pod number (&lt;code&gt;q6vl7&lt;/code&gt;, &lt;code&gt;qpjgf&lt;/code&gt;, and &lt;code&gt;vsxcv&lt;/code&gt; in this example).&lt;/p&gt;

&lt;p&gt;If everything is running, we should then be able to hit the service. To view the status of the service we would run &lt;code&gt;kubectl get service&lt;/code&gt; and see something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; kubectl get service
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP   PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;          AGE
my-service   LoadBalancer   10.106.118.92   localhost     8080:32361/TCP   44m
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If we hit that &lt;code&gt;External-IP&lt;/code&gt; with the port, we should see the same &lt;code&gt;Hello World&lt;/code&gt; we saw in the above 2 examples.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Well, we made it! I know there is a lot in here, and there is definitely a lot more, but hopefully this gives you enough pieces that you can start putting your own software together that can run on Kubernetes. Always feel free to reach out to me if you have question or comments.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>kubernetes</category>
      <category>node</category>
    </item>
    <item>
      <title>Setting up a Docker container on a Container-Optimized OS running on the Google Cloud</title>
      <dc:creator>Erik Lindblom</dc:creator>
      <pubDate>Mon, 11 Mar 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/baens/setting-up-a-docker-container-on-a-container-optimized-os-running-on-the-google-cloud-1iik</link>
      <guid>https://dev.to/baens/setting-up-a-docker-container-on-a-container-optimized-os-running-on-the-google-cloud-1iik</guid>
      <description>&lt;p&gt;Wow, that title looks like a mouth full doesn't it? So why do this? Isn't there Kubernetes for running Docker containers? Well, sometimes I only need just one container running and I really don't want to add the overhead of having to maintain another Kubernetes clusters. Lame excuse, but this works well for a small installation where I just don't need the power of a full Kubernetes cluster.&lt;/p&gt;

&lt;p&gt;What exactly is a Container-Optimized OS (COS)? Well, this OS is built by Google to be optimized for being the base operating system of a Kubernetes cluster or even just a simple Docker container. Its built upon the Chromium OS and has a lot of security features baked into it from the onset. For example, the root filesystem is mounted as read only. So the binaries that are on the system don't change, and can't be changed. Go ahead and &lt;a href="https://cloud.google.com/container-optimized-os/docs/"&gt;read all about it&lt;/a&gt;, the project is a great one.&lt;/p&gt;

&lt;p&gt;Here is what I will show you in this blog post. Throughout this blog post, we will use a base &lt;a href="https://hub.docker.com/_/nginx"&gt;Nginx Docker image&lt;/a&gt; as the container we want to run. We will first use some short cuts the &lt;code&gt;gcloud&lt;/code&gt; command provides to run a container on this image. We will then go through what would be required to get a image from a private repository up and running. Let's get started!&lt;/p&gt;

&lt;p&gt;All source code is &lt;a href="https://github.com/baens/code-examples-blog.baens.net/tree/cos-gcp-setup"&gt;hosted on github&lt;/a&gt; as well so you don't have to retype if you don't want too.&lt;/p&gt;

&lt;h1&gt;
  
  
  Perquisites
&lt;/h1&gt;

&lt;p&gt;This post will assume you have a Google cloud account all setup and a Google cloud project already carved out. If you haven't maybe follow the &lt;a href="https://cloud.google.com/compute/docs/quickstart-linux"&gt;quickstart tutorial&lt;/a&gt;, then come back.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Warning&lt;/em&gt;: I will be showing commands that create resources inside of a Google Cloud environment. That means real resources that cost real money. Be careful if you don't want to be charged.&lt;/p&gt;

&lt;h1&gt;
  
  
  Making gcloud do all the work
&lt;/h1&gt;

&lt;p&gt;Let's do something very basic, we will start up a container using the &lt;code&gt;gcloud&lt;/code&gt; commands to run a container on top of the COS VM. Here is what that &lt;code&gt;gcloud&lt;/code&gt; command looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcloud compute instances create-with-container nginx-vm --container-image nginx:1.15.8 --tags http-traffic
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Take note of the external IP address that is spit out after running that command. We will need that in the next step.&lt;/p&gt;

&lt;p&gt;Next we will need to expose that instance with a firewall rule:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcloud compute firewall-rules create allow-http-traffic --target-tags http-traffic --allow tcp:80
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Once that is complete, go ahead and try and hit the external IP address of that image. You should now see a "Welcome to nginx!" screen.&lt;/p&gt;

&lt;p&gt;Before the next part, if you want to delete that image, go ahead and run &lt;code&gt;gcloud compute instances delete nginx-vm&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Well that doesn't look hard does it? We can take images from docker hub and push them up, and bam, we have a running docker container running in the cloud. However, what happens if we want our own code, or code not hosted on the Docker hub? Let's create a private docker image and show you how to authenticate and pull that image down.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting up a custom Docker image
&lt;/h1&gt;

&lt;p&gt;Let's establish a private docker image that we would like to be running on the COS image. We will take the base nginx image, and modify it with a custom index page to demonstrate we can build and deploy the custom image.&lt;/p&gt;

&lt;p&gt;Here are the two files you will need, first the new &lt;code&gt;index.html&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Welcome to nginx!&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;style&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;35em&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Tahoma&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Verdana&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Arial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/style&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Welcome to My Custom nginx!&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And here is what the &lt;code&gt;Dockerfile&lt;/code&gt; would look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; nginx:1.15.8&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; index.html /usr/share/nginx/html&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you would like to test that locally, run &lt;code&gt;docker build -t test . &amp;amp;&amp;amp; docker run --rm -p 8080:80 test&lt;/code&gt; and point the browser to &lt;a href="http://localhost:8080"&gt;http://localhost:8080&lt;/a&gt;, you should see the "Welcome to My Custom nginx!" banner.&lt;/p&gt;

&lt;p&gt;Let's now take our image and push it up into the private repository. This is a little beyond the scope of this blog post, but go ahead and pick somewhere you can upload a docker image that can be accessed over the public internet. I've used gitlab but any registry really would work. Just make sure its accessible to the public. If you need help with that part, reach out to me and I'll attempt to assist.&lt;/p&gt;

&lt;h1&gt;
  
  
  Authenticating with the registry
&lt;/h1&gt;

&lt;p&gt;Now that we have our image up in a registry, we need some way to authenticate with that registry on our VM. If you were doing this locally, I bet you ran a &lt;code&gt;docker login&lt;/code&gt; command at some point to get authenticated with that registry. Well, thats exactly what we are going to do with this VM as well.&lt;/p&gt;

&lt;p&gt;So how do we going about running that command? Well, COS has a toolkit installed called &lt;a href="https://cloudinit.readthedocs.io/en/latest/"&gt;cloud-init&lt;/a&gt;. &lt;code&gt;Cloud-init&lt;/code&gt; is a set of tools to manage cloud images. These help provide ways to create startup scripts to get your cloud image running in exactly the way you want. They are used on most cloud providers and most distros have hooks or tools that can be used. For this particular case we will be interested in providing user scripts that can run at startup. For this, we will be providing a &lt;code&gt;user-data&lt;/code&gt; variable that provides a &lt;code&gt;cloud-config&lt;/code&gt; block. This block will create a user, a service definition, as well as run a startup script to start that service. Sounds easy right? Well, let's go!&lt;/p&gt;

&lt;p&gt;Let's take a look at what this &lt;code&gt;cloud-config&lt;/code&gt; configuration file may look like here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;#cloud-config&lt;/span&gt;

&lt;span class="na"&gt;users&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;cloudservice&lt;/span&gt;
  &lt;span class="na"&gt;uid&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2000&lt;/span&gt;

&lt;span class="na"&gt;write_files&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;/etc/systemd/system/myservice.service&lt;/span&gt;
  &lt;span class="na"&gt;permissions&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0644&lt;/span&gt;
  &lt;span class="na"&gt;owner&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;root&lt;/span&gt;
  &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
    &lt;span class="s"&gt;[Unit]&lt;/span&gt;
    &lt;span class="s"&gt;Description=My Service&lt;/span&gt;
    &lt;span class="s"&gt;Requires=docker.service network-online.target&lt;/span&gt;
    &lt;span class="s"&gt;After=docker.service network-online.target&lt;/span&gt;

    &lt;span class="s"&gt;[Service]&lt;/span&gt;
    &lt;span class="s"&gt;Environment="HOME=/home/cloudservice"&lt;/span&gt;
    &lt;span class="s"&gt;ExecStartPre=/usr/bin/docker login %REGISTRY% -u %USERNAME% -p %PASSWORD%&lt;/span&gt;
    &lt;span class="s"&gt;ExecStart=/usr/bin/docker run --network=host --rm --name=myservice %DOCKER_IMAGE%&lt;/span&gt;
    &lt;span class="s"&gt;ExecStop=/usr/bin/docker stop myservice&lt;/span&gt;
    &lt;span class="s"&gt;Restart=on-failure&lt;/span&gt;
    &lt;span class="s"&gt;RestartSec=10&lt;/span&gt;

    &lt;span class="s"&gt;[Install]&lt;/span&gt;
    &lt;span class="s"&gt;WantedBy=multi-user.target&lt;/span&gt;

&lt;span class="na"&gt;runcmd&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;iptables -A INPUT -p tcp -j ACCEPT&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;systemctl daemon-reload&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;systemctl enable --now --no-block myservice.service&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This configuration file is used as a template that will generate us a configuration file for our &lt;code&gt;cloud-config&lt;/code&gt; process. Let's point out some of the more important lines then I'll explain what the variables are:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 1&lt;/strong&gt;: This flags this file as a cloud config file. If you don't have this, the system won't pick it up and process it. It is VERY important to have it exactly this way.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 3 - 5&lt;/strong&gt;: Sets up a user dedicated to running this service. This creates a security sandbox because this user will not have any permissions assigned to it except to run this container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 7 - 26&lt;/strong&gt;: This is the file contents of &lt;code&gt;/etc/systemd/system/myservice.service&lt;/code&gt;. As the path suggests, this is a &lt;code&gt;systemd&lt;/code&gt; service file that will run our docker container. This section has information about the file permissions as well as the actual content of the file embedded in this configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 12 - 15&lt;/strong&gt;: Sets the description of the service as well as any requirements the service needs to run. In this case, we want the network to be online and docker to be running before this service starts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 17 - 23&lt;/strong&gt;: Sets how the service starts and stops. This is some of the more important bits. First, we are setting up the home directory to be the user that we had created earlier. This kinds of sandboxes and isolating where this is running. Next the &lt;code&gt;ExecStartPre&lt;/code&gt; is where some of this magic starts to come into place. This is where the &lt;code&gt;docker login&lt;/code&gt; command is executed. All of the parameters are currently variables and can be replaced but this is where the magic happens. Next the &lt;code&gt;ExecStart&lt;/code&gt; actually runs the &lt;code&gt;docker run&lt;/code&gt; command. One important thing to note is the &lt;code&gt;--network=host&lt;/code&gt; flag. We want the docker container to be using the host's network interfaces instead of creating the normal isolated network stack. This way the container can act just like the host on the network and have all ports exposed without any further magic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 22 - 23&lt;/strong&gt;: This sets up the service to restart on failure and wait 10 seconds between each retry&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 28 - 31&lt;/strong&gt;: This section runs once the configuration has been read and all other parts are completed. This acts like a startup script. First we setup the internal firewall to accept TCP connections using &lt;code&gt;iptables&lt;/code&gt;. Then we reload the &lt;code&gt;systemd&lt;/code&gt; daemon to read in our configuration files, then we enable and queue up startup of our service. This is really important to note,the &lt;code&gt;--now --no-block&lt;/code&gt; commands are important here because we want the service to start up now, but we also want it queued in the &lt;code&gt;systemd&lt;/code&gt; process so that it waits for the Docker service and network connects to be online. Otherwise our container may not start right because Docker isn't ready or we can't reach out to the internet to get our container.&lt;/p&gt;

&lt;p&gt;Now, what are all these variables for:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;%REGISTRY%&lt;/strong&gt;: This defines the root domain of where the registry is. For example, in testing this, I used gitlab so the registry would have been &lt;code&gt;registry.gitlab.com&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;%USERNAME%&lt;/strong&gt;: This is the username to be logged in as. Keeping with the gitlab theme, I used a deploy token and the username was given to me by gitlab.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;%PASSWORDD%&lt;/strong&gt;: This is the password or token that can be used to log in.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;%DOCKER_IMAGE%&lt;/strong&gt;: This is the docker image path. I.e. &lt;code&gt;registry.gitlab.com/myimage/test:1&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now, how do I run this? Well, replace all of the variables with the right values and then run this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gcloud compute instances create test-nginx --image cos-stable-72-11316-136-0 --image-project cos-cloud --tags http-traffic --metadata-from-file user-data=cloud-init-config.yml
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;If you take that IP address that is spit out by that command, you should see the "Welcome to My Custom nginx!" banner. If not, maybe read through the troubleshooting section. If everything worked, congratulations!&lt;/p&gt;

&lt;h1&gt;
  
  
  Notes on troubleshooting
&lt;/h1&gt;

&lt;p&gt;Alright, the site didn't come up. Now what? Well, let's first SSH into the box so we can start investigating what happened. To do that, let's make sure we have the firewall open by running this command: &lt;code&gt;gcloud compute firewall-rules create allow-ssh-traffic --allow tcp:22&lt;/code&gt;. This should open up the firewall to allow you to SSH into the box by executing the following command &lt;code&gt;gcloud compute ssh &amp;lt;box name, i.e. test-nginx&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Now that you are on the box, what exactly are you looking for? Well, for our docker example we want to make sure we have the docker container up and running so we would issue a &lt;code&gt;docker container ls&lt;/code&gt; command to verify it is up and running. If it is up and running, then you may have a firewall issue. Visit the &lt;a href="//console.cloud.google.com"&gt;console&lt;/a&gt; and inspect the network interface and see if the ingress is setup correctly. What we would like to see is that port 80 is open and working right. If it is, maybe the &lt;code&gt;iptables&lt;/code&gt; didn't run as expected so verify on the VM instance itself you can do something like &lt;code&gt;curl localhost&lt;/code&gt;. If that works, verify &lt;code&gt;iptables&lt;/code&gt; is correctly setup.&lt;/p&gt;

&lt;p&gt;But what if the container isn't even running? Where do I go from there? Well, we need to investigate the logs and start sifting through what may have happened. For this the &lt;code&gt;sudo journalctl&lt;/code&gt; command is what you start poking around in. This gives you all of the logs of the box as it starts. Another command for our example is the &lt;code&gt;sudo systemctl status myservice&lt;/code&gt; this shows you the raw status of the service, if its up or down, and what may be happening right now with the service.&lt;/p&gt;

&lt;p&gt;Another thing to check that I ran into a lot is first very that the cloud init script is even running correctly. A great way to check for that is to verify that the files we were expecting are even there. In this example, we would expect to see a file at &lt;code&gt;/etc/systemd/system/myservice.service&lt;/code&gt;. If that isn't there, usually the problem is that the very first line doesn't read &lt;code&gt;#cloud-config&lt;/code&gt; EXACTLY. Double check your config and consult the logs for &lt;code&gt;user-data&lt;/code&gt; parsing and retrieving. There is usually a log message that the file isn't understood from the variable and is ignoring the data.&lt;/p&gt;

&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;Hopefully I've given you a taste of how to setup a single Docker container instance using the Container-Optimized OS on the Google Cloud. I've found this a useful feature when I don't really need all the horse power of a kubernetes instance. This lighter weight infrastructure for a few containers provides to be useful and cost effective. But also be warned, these instances are obliviously not replicated in anyway, so if one goes down, it is all down. Be careful in the cloud because every stack should be built on the assumption that cloud resources could come and go at will.&lt;/p&gt;

&lt;p&gt;All of this code and examples are &lt;a href="https://github.com/baens/code-examples-blog.baens.net/tree/cos-gcp-setup"&gt;hosted on my github account&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>gcp</category>
    </item>
    <item>
      <title>Making Inspec with SSH work with Packer on the Google Cloud Platform</title>
      <dc:creator>Erik Lindblom</dc:creator>
      <pubDate>Fri, 11 Jan 2019 00:00:00 +0000</pubDate>
      <link>https://dev.to/baens/making-inspec-with-ssh-work-with-packer-on-the-google-cloud-platform-16gm</link>
      <guid>https://dev.to/baens/making-inspec-with-ssh-work-with-packer-on-the-google-cloud-platform-16gm</guid>
      <description>&lt;p&gt;&lt;em&gt;This entry was originally published on my blog at &lt;a href="https://blog.baens.net/posts/making-inspec-work-with-gcp-and-packer/"&gt;blog.baens.net&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Background
&lt;/h1&gt;

&lt;p&gt;This blog post aims to help anyone trying to make a &lt;a href="https://www.packer.io/"&gt;Packer&lt;/a&gt; image, tested with &lt;a href="https://www.inspec.io/"&gt;Inspec&lt;/a&gt;, on the &lt;a href="https://cloud.google.com/"&gt;Google Cloud Platform&lt;/a&gt;. I have recently been using the these tools for my day-to-day and I wanted to make these three tools work together, which was surprisingly difficult. This blog post will hopefully help anyone out there that may be trying todo the same.&lt;/p&gt;

&lt;p&gt;What I want from these tools is have Packer spin up a new VM, run all the build steps, then test that VM with Inspec. Also, I didn't want to clutter up the VM with anything more installed then it really needed, so I didn't want Inspec running with all of its tools installed on the new VM. That means I wanted Inspec to run from my box then connect through SSH to the new box. Sounds simple right? Well, there were enough gotchas and lack of search resources out there that I felt I needed to write this up.&lt;/p&gt;

&lt;p&gt;So enough yap, let's see what the code looks like. If you want to see everything put together, &lt;a href="https://github.com/baens/code-examples-blog.baens.net/tree/packer-gcp-ssh-key"&gt;code repository here&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  The problems I faced
&lt;/h1&gt;

&lt;p&gt;So let me walk through the problems I encountered along this journey that I will try and demonstrate answers to.&lt;/p&gt;

&lt;p&gt;Problem #1: The first problem I hit was that I needed Inspec to talk to the new VM, but Packer doesn't provide those variables very easily. What I needed was the host IP of the VM running in the cloud. Since Packer didn't provide that out of the box, I had to figure out a way to get around that.&lt;/p&gt;

&lt;p&gt;Problem #2: Once I did establish a connection, I then needed to authenticate Inspec with the VM. Inspec could natively connect over SSH, so creating and establishing a SSH key to login with was the obvious choice. However, Packer again didn't provide a convenient way of doing this so I need to establish that key myself and set a few manual things to make that work.&lt;/p&gt;

&lt;h1&gt;
  
  
  Solving Problem 1: Getting the IP of the Packer VM in GCP
&lt;/h1&gt;

&lt;p&gt;This sounds easy enough but is surprising difficult: how do I get the IP of the currently running VM that Packer is communicating with? One approach might ping some remote web site that tell you your public IP, but that seems ridiculous to introduce another layer outside of your control. My search stumbled upon a number of examples of how to do this on AWS but very little on GCP. However, people using AWS did give me an idea of what todo, or at the very least what to search for.&lt;/p&gt;

&lt;p&gt;What people use on AWS often is called the Metadata server. The Metadata server is a service for every VM running on &lt;a href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html"&gt;AWS&lt;/a&gt; (and &lt;a href="https://cloud.google.com/compute/docs/storing-retrieving-metadata"&gt;GCP&lt;/a&gt;) that can tell you about the instance you are running on. This was the thing I needed, I found the &lt;a href="https://cloud.google.com/compute/docs/storing-retrieving-metadata"&gt;documentation for GCP&lt;/a&gt; and sure enough, it had information on all of the exposed IP addresses. The particular address I needed was located at this URL: &lt;code&gt;http://metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip&lt;/code&gt;. And whats even better was that this was generic across instances so I didn't have to do some fancy logic depending on the box. &lt;/p&gt;

&lt;p&gt;Now that I have the HTTP address of where I can get the external IP address, how would I exactly retrieve that information from the command line. Thankfully, curl was already installed so I crafted this command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl  -H \"Metadata-Flavor: Google\" metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And executed that and viola, the IP address I needed. &lt;/p&gt;

&lt;p&gt;Now, something to be pointed out. That HTTP header we added (&lt;code&gt;Metadata-Flavor: Google&lt;/code&gt;) is required. This is a safe guard to protect you incase you accidentally point something wrong to this location. &lt;/p&gt;

&lt;p&gt;Now that I have my IP address, how do I use it? Again, long searches didn't show a way to pipeline variables from one Packer step to another so what was I going todo? I'm not 100% sure how I stumbled upon but I found a very neat trick of downloading the file after you created it. Here is what that will look like in Packer's provisioning steps:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"provisioners"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shell"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"inline"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"curl -H &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Metadata-Flavor: Google&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip &amp;gt; /tmp/ip"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"download"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/tmp/ip"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"destination"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./host"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And that solved the problem. Just have to create a file with data from a special internal endpoint, then download that file for use in next steps. Easy! Or at least easy once you work it out. Go figure!&lt;/p&gt;

&lt;h1&gt;
  
  
  Solving Problem 2: Communicating over SSH
&lt;/h1&gt;

&lt;p&gt;Now that I had the IP address, I need to communicate from Inpsec to that IP. Inspec has several ways of communicating with the machine. It can do it locally or even execute on a remote machine. I wanted to execute locally but communicate on the remote machine so that I didn't have to install anything on the remote box. This lead me down the path that I needed to use SSH to communicate with that remote box. By default SSH requires a username and password, and since I was going to be using this in an automated build environment. Having something prompt for a username and password wasn't going to fly, never mind the fact that isn't very secure either. So I need to setup a SSH key somehow in the automated process to get logged into the remote box.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://cloud.google.com/compute/docs/instances/adding-removing-ssh-keys#edit-ssh-metadata"&gt;Google cloud provides a way for you to provide a SSH key&lt;/a&gt; that will get installed on the box for you to use. So first let's generate the key. The way Google parses the key information is it looks for comments inside of the key for which user is associated with this. Here is the command I use to generate the key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-f&lt;/span&gt; inspec-key &lt;span class="nt"&gt;-C&lt;/span&gt; packer &lt;span class="nt"&gt;-N&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt; &lt;span class="nt"&gt;-m&lt;/span&gt; PEM
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The command will output a set of SSH key files called &lt;code&gt;inspec-key&lt;/code&gt; with a comment of &lt;code&gt;packer&lt;/code&gt; and the &lt;code&gt;-N&lt;/code&gt; flag is the password to be used (blank in this case). You need to specify the PEM format because some of the Ruby modules that will be loaded can't parse newer OpenSSH key formats. &lt;/p&gt;

&lt;p&gt;Alright, I now have my SSH key, now I need to place that SSH key for Packer to use when it creates the VM instance. For that you need to modify the builder with a few parameters. Here is what the builder turns into:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="nl"&gt;"builders"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"googlecompute"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"ssh-keys"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"packer:{{user `inspec-key`}}"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="err"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And here is what the command would look like to run Packer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;packer build &lt;span class="nt"&gt;-var&lt;/span&gt; inspec-key&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cat &lt;/span&gt;inspec-key.pub&lt;span class="si"&gt;)&lt;/span&gt; image.json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;metadata/ssh-keys&lt;/code&gt; is the important part. You add the metadata with the username, then the contents of the key. This tripped me up at first because I thought the key had already been setup with all of the relevant information, but trial and error found the right format. And just to be clear, the format is &lt;code&gt;&amp;lt;username&amp;gt;:&amp;lt;ssh public key data&amp;gt;&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Alright, now that we have our new instance up and running, how do we connect Inspec? Well, again, I didn't really want to have to install another tool so let's use docker to run the actual tool. The docker command will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:/workspace &lt;span class="nt"&gt;-w&lt;/span&gt; /workspace chef/inspec:3.2.7 detect &lt;span class="nt"&gt;-t&lt;/span&gt; ssh://packer@&lt;span class="si"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;cat &lt;/span&gt;host &lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; inspec-key
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Few things to explain in this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-v $(pwd):/workspace -w /workspace&lt;/code&gt; - Take your current directory and mount it at &lt;code&gt;/workspace&lt;/code&gt; and make the current directory when the docker container is running inside of that directory.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;chef/inspec:3.2.7 detect&lt;/code&gt; - The docker image and the command to run. For the demo I used &lt;code&gt;detect&lt;/code&gt; just to show you it connects. When you actually want to run tests you run &lt;code&gt;exec&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-t ssh://packer@$( cat host ) -i inspec-key&lt;/code&gt; - Here are a few of the magic bits. Tell Inspect to connect through &lt;code&gt;ssh&lt;/code&gt; with the data from the &lt;code&gt;host&lt;/code&gt; file we downloaded in the previous step. Next, use the &lt;code&gt;inspec-key&lt;/code&gt; file we created earlier. &lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  The resulting Packer file and the test run
&lt;/h1&gt;

&lt;p&gt;Alright, all together this will look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"builders"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"googlecompute"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"project_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"{{user `gcp-project`}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"source_image_family"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ubuntu-1804-lts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"zone"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"us-central1-a"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"image_description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Image demo for SSH keys"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"ssh_username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"packer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"tags"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"packer"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"image_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"test-image-{{isotime | clean_image_name}}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"metadata"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"enable-oslogin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"false"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"ssh-keys"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"packer:{{user `inspec-key`}}"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"provisioners"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shell"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"inline"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"curl metadata.google.internal/computeMetadata/v1/instance/network-interfaces/0/access-configs/0/external-ip -H &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Metadata-Flavor: Google&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; &amp;gt; /tmp/ip"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"file"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"direction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"download"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"source"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/tmp/ip"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"destination"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"./host"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"shell-local"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"command"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"docker run --rm -v $(pwd):/workspace -w /workspace chef/inspec:3.2.7 detect -t ssh://packer@$( cat host ) -i inspec-key"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The builder is setup with our keys for us to connect. The tool then downloads the IP of the server, and we use that with Inspec to connect to the host. It should look something like this when it runs:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UiIn9ByH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.baens.net/images/cloud-build.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UiIn9ByH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://blog.baens.net/images/cloud-build.gif" alt="Demo of the build"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.baens.net/images/cloud-build.gif"&gt;Link to gif of the build, something messed up on dev.to&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/baens/code-examples-blog.baens.net/tree/packer-gcp-ssh-key"&gt;All source code can be found on github if you want to run this yourself.&lt;/a&gt;&lt;/p&gt;

</description>
      <category>devops</category>
      <category>packer</category>
      <category>inspec</category>
      <category>gcp</category>
    </item>
    <item>
      <title>Dockerize the Kotlin toolchain</title>
      <dc:creator>Erik Lindblom</dc:creator>
      <pubDate>Mon, 31 Dec 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/baens/dockerize-the-kotlin-toolchain-1d0m</link>
      <guid>https://dev.to/baens/dockerize-the-kotlin-toolchain-1d0m</guid>
      <description>&lt;p&gt;&lt;em&gt;This entry was originally published on my blog at &lt;a href="https://blog.baens.net/posts/dockerize-kotlin-toolchain/"&gt;blog.baens.net&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Am I crazy? Yes, yes I am. For what ever reason, I love the idea of a project that I can literally move from computer to computer very few things installed and be able to be productive in that code base. By this, I mean I could install, one, maybe two tools and then I can be productive in a code base. Right now, &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; feels like maybe I can achieve this crazy dream.&lt;/p&gt;

&lt;p&gt;With this crazy idea in mind, I decided if I could fully dockerize the &lt;a href="https://kotlinlang.org/"&gt;Kotlin&lt;/a&gt; tool chain. In theory I can setup a workstation by installing an editor, git, docker, and bam. I'm now 100% ready to code on this machine. Alright, with this, off we go.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1: Getting the basic build working
&lt;/h1&gt;

&lt;p&gt;Now, to make things easy, I am going to reuse my &lt;a href="https://blog.baens.net/posts/step-by-step-kotlin/"&gt;Kotlin base&lt;/a&gt; and recreate this project with this tool chain. First step, let's replace the &lt;code&gt;gradlew&lt;/code&gt; file with a docker executed gradle file. It will look something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env sh&lt;/span&gt;

docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:/workspace &lt;span class="nt"&gt;-w&lt;/span&gt; /workspace gradle:5.0.0-jdk11 gradle &lt;span class="nv"&gt;$@&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This is a fairly straight forward &lt;code&gt;docker&lt;/code&gt; command, but just in case you have never used &lt;code&gt;docker&lt;/code&gt; before let me touch on some of the basics:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;docker run&lt;/code&gt; - we are going to run a docker image&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--rm -it&lt;/code&gt; - remove (&lt;code&gt;rm&lt;/code&gt;) once completed and add standard input pipes (&lt;a href="https://docs.docker.com/engine/reference/commandline/run/#assign-name-and-allocate-pseudo-tty---name--it"&gt;&lt;code&gt;it&lt;/code&gt;&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-v&lt;/code&gt; - mount our current workspace into the directory inside the container at &lt;code&gt;/workspace&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-w&lt;/code&gt; - make the current working direction &lt;code&gt;/workspace&lt;/code&gt; (i.e. &lt;code&gt;cd /workspace&lt;/code&gt; at start)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gradle:5.0.0-jdk11&lt;/code&gt; - use gradle 5.0.0 with the JDK 11 image (see a whole list of tags on the &lt;a href="https://hub.docker.com/_/gradle/"&gt;gradle docker hub&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gradle&lt;/code&gt; - execute the gradle command&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;$@&lt;/code&gt; - pass all arguments from the parent shell to this command&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alright, let's test this and see what happens!&lt;/p&gt;


    


&lt;p&gt;Now, don't be too alarmed if your output is not &lt;em&gt;&lt;em&gt;exactly&lt;/em&gt;&lt;/em&gt; the same. I had already ran it so the docker download process isn't going, but it should be fairly close after that.&lt;/p&gt;

&lt;p&gt;Looks like we have some jars, let's get them into a container and run them!&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 2: Put into jar into Docker
&lt;/h1&gt;

&lt;p&gt;Now, I currently had a &lt;code&gt;Dockerfile&lt;/code&gt; that built the jar, then created the docker image, I am going to continue that idea. Here is what the &lt;code&gt;Dockerfile&lt;/code&gt; looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; gradle:5.0.0-jdk11 as BUILD&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; /home/gradle/src
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /home/gradle/src&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . /home/gradle/src&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;gradle &lt;span class="nt"&gt;--no-daemon&lt;/span&gt; shadowJar

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; openjdk:11.0.1-jre&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=BUILD /home/gradle/src/build/libs/step-by-step-kotlin-all.jar /bin/runner/run.jar&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /bin/runner&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["java","-jar","run.jar"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;I'm not going to go much into this file since I already explained it in the other blog post, but let me point out that line 3 was special and needed. The permissions were a little wonky inside of the container and I had to make sure the folder was already created correctly. There are many many work around for this, but I didn't want to demonstrate that.&lt;/p&gt;

&lt;p&gt;Let's build and run this now!&lt;/p&gt;


    


&lt;p&gt;Excellent! It worked as expected. But dang is it slow. Let's try really quick and fix that. &lt;/p&gt;

&lt;h1&gt;
  
  
  Step 3: build time improvements
&lt;/h1&gt;

&lt;p&gt;Ok, obviously the build loop on this is a tad bit ridiculous. Let me show you one quick improvement for build times. If you watched closely to the video, the downloading of plugins and other artifacts is by the largest amount of time spent. This should be easily fixed if we just cached those artifacts and let gradle discover them each time. The gradle tool does this natively by storing in your home directly this folder, so why don't we just create a folder that can live between each gradle run? Well, here's what the &lt;code&gt;gradlew&lt;/code&gt; turns into if we want to do exactly that:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env sh&lt;/span&gt;

&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; .build_cache &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;mkdir&lt;/span&gt; .build_cache
docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:/workspace &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/build_cache:/home/gradle/.gradle &lt;span class="nt"&gt;-w&lt;/span&gt; /workspace gradle:5.0.0-jdk11 gradle &lt;span class="nt"&gt;--no-daemon&lt;/span&gt; &lt;span class="nv"&gt;$@&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Nothing wild. Just create the &lt;code&gt;build_cache&lt;/code&gt; folder and then mount that folder inside of the docker image where it would be expected. My quick tests show we go from 30 seconds to 8 second builds. Not bad.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 4: .....Profit??.... Evaluating if this is practical
&lt;/h1&gt;

&lt;p&gt;Well, now that we have this sort of working and are producing builds, is this really practical? Well, honestly, its pretty close. It works, you don't need many things installed. There are some further speed improvements you could get with some tweaks. I would use (and I sort of use a setup for some projects like this now) this setup as my own setup, but I may not push it on other devs to use it unless they wanted to. But I'm starting to like this kind of setup. Again, there are many hiccups with this approach, but it gets pretty close.&lt;/p&gt;

&lt;p&gt;So, this has at least been a fun adventure of seeing if this was possible and I think it shows promise into where things may go. &lt;/p&gt;

&lt;h1&gt;
  
  
  Special Notes
&lt;/h1&gt;

&lt;p&gt;If you checkout the code, you may notice a &lt;code&gt;.dockerignore&lt;/code&gt; file. This file tells docker what not to include when it is moving files over to the docker context. This is pretty important because the &lt;code&gt;.gradle&lt;/code&gt; folder doesn't share well across the machines and things start breaking. &lt;/p&gt;

</description>
      <category>docker</category>
      <category>kotlin</category>
    </item>
    <item>
      <title>Setting up a development workspace for Postgres and vault</title>
      <dc:creator>Erik Lindblom</dc:creator>
      <pubDate>Wed, 13 Jun 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/baens/setting-up-a-development-workspace-for-postgres-and-vault-439p</link>
      <guid>https://dev.to/baens/setting-up-a-development-workspace-for-postgres-and-vault-439p</guid>
      <description>&lt;p&gt;&lt;em&gt;This entry was originally published on my blog at &lt;a href="https://blog.baens.net/posts/postgres-vault-dev-workspace/"&gt;blog.baens.net&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;My current line of work has led me to start getting into docker more and more. One of the neat things I've been getting to play with is using &lt;a href="https://www.postgresql.org/"&gt;Postgres&lt;/a&gt; as my database and &lt;a href="https://www.vaultproject.io/"&gt;Vault&lt;/a&gt; for secrets management. I figured it was time to showcase what a basic development workspace looks like to help get someone up and running quickly.&lt;/p&gt;

&lt;p&gt;I've hopefully boiled this down into the smallest pieces needed to make things work. This allows a new developer on a project to run &lt;code&gt;docker-compose up&lt;/code&gt; which will bring up a working development environment.&lt;/p&gt;

&lt;p&gt;I will guide you first through some setup scripts that are needed, then tie them all together in the &lt;code&gt;docker-compose.yml&lt;/code&gt; file.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting up Postgres with SSL
&lt;/h1&gt;

&lt;p&gt;One of requirements I've had to fill is that I need a running Postgres instance with SSL turned on. To create the needed SSL files I've created this script to create all the necessary files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;# Creates SSL certificates need for postgres&lt;/span&gt;

&lt;span class="nv"&gt;OUTPUT_FOLDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$0&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/../run/ssl-files"&lt;/span&gt;

&lt;span class="nb"&gt;mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$OUTPUT_FOLDER&lt;/span&gt;

&lt;span class="nv"&gt;OUTPUT_FOLDER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUTPUT_FOLDER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;basename&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OUTPUT_FOLDER&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"SSL files output folder [&lt;/span&gt;&lt;span class="nv"&gt;$OUTPUT_FOLDER&lt;/span&gt;&lt;span class="s2"&gt;]"&lt;/span&gt;

&lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; &lt;span class="nv"&gt;$OUTPUT_FOLDER&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="nv"&gt;OPENSSL_COMMAND&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"docker run --rm -it -w /out -v &lt;/span&gt;&lt;span class="nv"&gt;$OUTPUT_FOLDER&lt;/span&gt;&lt;span class="s2"&gt;:/out svagi/openssl"&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;### Create CA ###"&lt;/span&gt;
&lt;span class="nv"&gt;$OPENSSL_COMMAND&lt;/span&gt; req &lt;span class="nt"&gt;-new&lt;/span&gt; &lt;span class="nt"&gt;-x509&lt;/span&gt; &lt;span class="nt"&gt;-nodes&lt;/span&gt; &lt;span class="nt"&gt;-newkey&lt;/span&gt; rsa &lt;span class="nt"&gt;-out&lt;/span&gt; ca.pem &lt;span class="nt"&gt;-keyout&lt;/span&gt; ca-key.pem &lt;span class="nt"&gt;-set_serial&lt;/span&gt; 01 &lt;span class="nt"&gt;-batch&lt;/span&gt; &lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s2"&gt;"/CN=ssl-server"&lt;/span&gt;
&lt;span class="nv"&gt;$OPENSSL_COMMAND&lt;/span&gt; rsa &lt;span class="nt"&gt;-in&lt;/span&gt; ca-key.pem &lt;span class="nt"&gt;-out&lt;/span&gt; ca-key.pem

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;### Create postgres server key ###"&lt;/span&gt;
&lt;span class="nv"&gt;$OPENSSL_COMMAND&lt;/span&gt; req &lt;span class="nt"&gt;-new&lt;/span&gt; &lt;span class="nt"&gt;-newkey&lt;/span&gt; rsa &lt;span class="nt"&gt;-keyout&lt;/span&gt; server-key.pem &lt;span class="nt"&gt;-out&lt;/span&gt; server-req.pem &lt;span class="nt"&gt;-passout&lt;/span&gt; pass:abcd &lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s2"&gt;"/CN=postgres-ssl-server"&lt;/span&gt;
&lt;span class="nv"&gt;$OPENSSL_COMMAND&lt;/span&gt; rsa &lt;span class="nt"&gt;-in&lt;/span&gt; server-key.pem &lt;span class="nt"&gt;-out&lt;/span&gt; server-key.pem &lt;span class="nt"&gt;-passin&lt;/span&gt; pass:abcd
&lt;span class="nv"&gt;$OPENSSL_COMMAND&lt;/span&gt; x509 &lt;span class="nt"&gt;-req&lt;/span&gt; &lt;span class="nt"&gt;-in&lt;/span&gt; server-req.pem &lt;span class="nt"&gt;-CA&lt;/span&gt; ca.pem &lt;span class="nt"&gt;-CAkey&lt;/span&gt; ca-key.pem &lt;span class="nt"&gt;-set_serial&lt;/span&gt; 02 &lt;span class="nt"&gt;-out&lt;/span&gt; server-cert.pem

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n\n&lt;/span&gt;&lt;span class="s2"&gt;### Create client key ###"&lt;/span&gt;
&lt;span class="nv"&gt;$OPENSSL_COMMAND&lt;/span&gt; req &lt;span class="nt"&gt;-new&lt;/span&gt; &lt;span class="nt"&gt;-newkey&lt;/span&gt; rsa &lt;span class="nt"&gt;-keyout&lt;/span&gt; client-key.pem &lt;span class="nt"&gt;-out&lt;/span&gt; client-req.pem &lt;span class="nt"&gt;-passout&lt;/span&gt; pass:abcd &lt;span class="nt"&gt;-subj&lt;/span&gt; &lt;span class="s2"&gt;"/CN=postgres-ssl-server"&lt;/span&gt;
&lt;span class="nv"&gt;$OPENSSL_COMMAND&lt;/span&gt; rsa &lt;span class="nt"&gt;-in&lt;/span&gt; client-key.pem &lt;span class="nt"&gt;-out&lt;/span&gt; client-key.pem &lt;span class="nt"&gt;-passin&lt;/span&gt; pass:abcd
&lt;span class="nv"&gt;$OPENSSL_COMMAND&lt;/span&gt; x509 &lt;span class="nt"&gt;-req&lt;/span&gt; &lt;span class="nt"&gt;-in&lt;/span&gt; client-req.pem &lt;span class="nt"&gt;-CA&lt;/span&gt; ca.pem &lt;span class="nt"&gt;-CAkey&lt;/span&gt; ca-key.pem &lt;span class="nt"&gt;-set_serial&lt;/span&gt; 03 &lt;span class="nt"&gt;-out&lt;/span&gt; client-cert.pem

&lt;span class="nb"&gt;chmod &lt;/span&gt;0600 &lt;span class="nv"&gt;$OUTPUT_FOLDER&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;

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

&lt;/div&gt;



&lt;p&gt;This file assumes we are in a subfolder and will be creating a &lt;code&gt;run/ssl-files&lt;/code&gt; folder above it and drops all the commands in there. To make things easier and more portable, I'm using Docker as the tool to bring in openssl command instead of getting it installed locally. &lt;/p&gt;

&lt;h1&gt;
  
  
  Configuring Postgres
&lt;/h1&gt;

&lt;p&gt;The next script I have is to configure postgres correctly. This will add those SSL files and make sure only SSL connections are accepted. This looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Setting up postgres hba settings"&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOM&lt;/span&gt;&lt;span class="sh"&gt; &amp;gt; &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PGDATA&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;/pg_hba.conf
local     all  all       trust
hostnossl all  all  all  reject
hostssl   all  all  all  password
&lt;/span&gt;&lt;span class="no"&gt;EOM

&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Adding SSL settings to postgresql.conf file"&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="no"&gt;EOM&lt;/span&gt;&lt;span class="sh"&gt; &amp;gt;&amp;gt; &lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;PGDATA&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;/postgresql.conf
ssl = on
ssl_cert_file = '/var/ssl/server-cert.pem'
ssl_key_file = '/var/ssl/server-key.pem'
ssl_ca_file = '/var/ssl/ca.pem'
&lt;/span&gt;&lt;span class="no"&gt;EOM
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script is intended to be run inside of the docker setup routine which we will get to in a minute. The &lt;code&gt;pg_hba.conf&lt;/code&gt; file is to ensure that only ssl connections are accepted and the &lt;code&gt;postgresql.conf&lt;/code&gt; file is adding the SSL settings needed for that.&lt;/p&gt;

&lt;p&gt;This script will be run when we start up postgres and will be configured in our &lt;code&gt;docker-compose.yml&lt;/code&gt; file. We will get to that in just a minute. &lt;/p&gt;

&lt;h1&gt;
  
  
  Seeding vault
&lt;/h1&gt;

&lt;p&gt;The next script is related to Vault. This script will start vault then configure vault to be able to create secrets for our database. The script looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="c"&gt;# Run a vault dev server and configure that instance for the database&lt;/span&gt;

&lt;span class="c"&gt;# Capture the token defined in the environment and make it our dev server token so they match&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;VAULT_DEV_ROOT_TOKEN_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$VAULT_TOKEN&lt;/span&gt;

&lt;span class="c"&gt;# Start vault server and place in background&lt;/span&gt;
vault server &lt;span class="nt"&gt;-dev&lt;/span&gt; &amp;amp;

&lt;span class="c"&gt;# Wait for server to start&lt;/span&gt;
&lt;span class="nb"&gt;sleep &lt;/span&gt;2

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Enabling database plugin"&lt;/span&gt;
vault secrets &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;dbs database

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Adding postgres connection information"&lt;/span&gt;
vault write dbs/config/mydb &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;plugin_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;postgresql-database-plugin &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;connection_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'postgresql://{{username}}:{{password}}@database:5432/mydb'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;allowed_roles&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mydb-admin &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"admin"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"secret"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;verify_connection&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;false

echo&lt;/span&gt; &lt;span class="s2"&gt;"Adding admin role"&lt;/span&gt;
vault write dbs/roles/mydb-admin &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;db_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;mydb &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;default_ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;5m &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;max_ttl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1h &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nv"&gt;creation_statements&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"CREATE ROLE &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;{{name}}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; WITH LOGIN PASSWORD '{{password}}' &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
                         VALID UNTIL '{{expiration}}'; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;
                         GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;{{name}}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;;"&lt;/span&gt;

&lt;span class="c"&gt;# Wait for vault server to finish&lt;/span&gt;
&lt;span class="nb"&gt;wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This script is intended to be run when the vault container starts. This means that this script is responsible to ensure the server starts and stays running. Once that is complete, we then write out our configuration using the &lt;code&gt;vault&lt;/code&gt; command. After that is all done, we let the script hang with the &lt;code&gt;vault server&lt;/code&gt; portion with the &lt;code&gt;wait&lt;/code&gt; command. This is because the script is what actually started the server and when this script ends, so will the docker container.  &lt;/p&gt;

&lt;p&gt;One of the first bits in the script is to take &lt;code&gt;VAULT_TOKEN&lt;/code&gt; variable that is passed and make that our dev server token. Now, a Vault token is your key in getting things out of vault. To ensure that we know the key, instead of doing the default behavior of generating a random key, we tell the server which token to use. And to make it even easier, we let the docker container pass us one token through &lt;code&gt;VAULT_TOKEN&lt;/code&gt; and we tie that to the &lt;code&gt;VAULT_DEV_ROOT_TOKEN_ID&lt;/code&gt; so we don't have to define that twice. And just to be extra clear, &lt;code&gt;VAULT_TOKEN&lt;/code&gt; is what a client uses, the &lt;code&gt;VAULT_DEV_ROOT_TOKEN_ID&lt;/code&gt; is what the server itself uses. If we didn't provide that dev token, the server would generate a random token that makes it a lot harder to development against. This is the difference between our dev Vault instance and a production one. In dev, we can define that token up front, in production, those are randomly generated for you.  &lt;/p&gt;

&lt;p&gt;The next interesting bits are the connection and role setup. One quick thing I want to point out that the paths follow a pattern. The name &lt;code&gt;dbs&lt;/code&gt; comes from where we enabled the database plugin. There are then 3 sub paths of that, &lt;code&gt;config&lt;/code&gt;, &lt;code&gt;roles&lt;/code&gt; and &lt;code&gt;creds&lt;/code&gt;. The &lt;code&gt;config&lt;/code&gt; path is where the configuration to our database is stored. Next we add to the &lt;code&gt;roles&lt;/code&gt; part which defines what roles can create credentials to our database with the config. Then there is a &lt;code&gt;creds&lt;/code&gt; key that actually creates the credentials when it is read, more on using that later. &lt;/p&gt;

&lt;p&gt;To reiterate we store configuration in &lt;code&gt;dbs/config/mydb&lt;/code&gt;, we store role information in &lt;code&gt;dbs/roles/mydb-admin&lt;/code&gt;. This automatically creates a path at &lt;code&gt;dbs/creds/mydb-admin&lt;/code&gt; that we will use later to get our credentials.&lt;/p&gt;

&lt;p&gt;The postgres credentials use and management is worth a blog post all together but let me talk about this really quick. With Vault, we are creating temporary roles that will come and go at will. When we use those credentials from Vault to also manage the schema (e.g. creating tables), we need to pay extra close attention on who actually owns those tables. When you create a table, who ever the role is that you are currently working as is the role that will be the owner of said table. Then, your next role will have issues actually accessing that table unless permissions and ownership have been setup correctly. I have a &lt;a href="https://dba.stackexchange.com/q/208649/16141"&gt;dba.stackexchange&lt;/a&gt; question related this that will have a longer blog post later.&lt;/p&gt;

&lt;h1&gt;
  
  
  Docker-compose setup
&lt;/h1&gt;

&lt;p&gt;The &lt;code&gt;docker-compose.yml&lt;/code&gt; file that binds all of these together 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;version: '3'
services:
  database:
    image: postgres:9.6
    volumes:
      - ./run/ssl-files:/var/ssl/
      - ./scripts/setup-postgres:/docker-entrypoint-initdb.d/setup.sh
    ports:
      - 5432:5432
    environment:
      - POSTGRES_USER=admin
      - POSTGRES_PASSWORD=secret
      - POSTGRES_DB=mydb
  vault:
      image: vault:0.10.1
      ports:
        - 8200:8200
      environment:
        - VAULT_TOKEN=secret-token
        - VAULT_ADDR=http://127.0.0.1:8200/
      volumes:
        - ./scripts/setup-and-run-vault:/setup-and-run.sh
      command: /setup-and-run.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's step through this line by line.&lt;/p&gt;

&lt;p&gt;Line 1 &amp;amp; 2 are just normal Docker compose file format stuff.&lt;/p&gt;

&lt;p&gt;The next 3 sections are the 3 different services we will be running. Postgres the database is defined in lines 3 - 13 and the Vault service is defined in 14 - 23.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;database&lt;/code&gt; section is a fairly straight forward postgres docker setup. We add the SSL files to the docker container (line 6) and the script to be run on startup (line 7). We also expose the ports to other apps that I am developing can actually hit this when it is running (line 9). The last bits are environment variables to setup the initial database (line 11 - 13). Those last ones you can tweak to what ever you desire, these are just some defaults I've picked.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;vault&lt;/code&gt; section is mostly straight forward. In the environment variables (starting line 20) we have two definitions, one for our token, another one for the address of the running vault instance. The first is the token we use for our dev server as well as accessing that server (remember: we define the token and use it in our script for the dev server). The next variable needs to be defined because by default vault will try and use https. Looks kind of silly that you need to define the local server, but that's alright. The &lt;code&gt;volume&lt;/code&gt; section adds our script to the container from our local disk, and then we override the default command to run that script.&lt;/p&gt;

&lt;h1&gt;
  
  
  Actually using this
&lt;/h1&gt;

&lt;p&gt;Alright, we now have all of this crazy stuff, how exactly do I use any of this? Well, let's demonstrate that with running inside of this local project, not connecting any code. Just making sure things are running and that we can demonstrate they are running.&lt;/p&gt;

&lt;p&gt;First, how do I start this up? Well run &lt;code&gt;docker-compose up&lt;/code&gt;. This brings the whole system up. The whole point of what we did before with the seeding and such is that one command will give you a working system. If you go read through all of the output that gives you, you will see that the database was started and initialized and vault was started and initialize. &lt;/p&gt;

&lt;p&gt;Next, let's go ahead and see how to connect to the database. One neat way is we can actually get connected to our running instance and execute &lt;code&gt;psql&lt;/code&gt; through that. You can do that by &lt;code&gt;docker-compose exec database psql -U admin -d mydb&lt;/code&gt;. If you ran that, you should now be inside of &lt;code&gt;psql&lt;/code&gt; prompt that is connect to the database.  &lt;/p&gt;

&lt;p&gt;However, that isn't the fun part with vault. What if I wanted to try out using the whole pipeline of vault creating a credential, then getting into the database with those credentials? Well, its a bit more complicated but here is a script that goes through that process:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nv"&gt;VAULT_SETTINGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;docker-compose &lt;span class="nb"&gt;exec &lt;/span&gt;vault vault &lt;span class="nb"&gt;read&lt;/span&gt; &lt;span class="nt"&gt;--format&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;json dbs/creds/mydb-admin&lt;span class="si"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;VAULT_USERNAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$VAULT_SETTINGS&lt;/span&gt; | docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-i&lt;/span&gt; colstrom/jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.data.username'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
docker-compose &lt;span class="nb"&gt;exec &lt;/span&gt;database psql &lt;span class="nt"&gt;-U&lt;/span&gt; &lt;span class="nv"&gt;$VAULT_USERNAME&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt; mydb
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first part is capturing a vault token by executing &lt;code&gt;vault read&lt;/code&gt; inside of one of the &lt;code&gt;vault&lt;/code&gt; container. This will create a JSON object that looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"request_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"92b63ef7-9ed1-c669-cb36-16ac8110f7c2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lease_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"dbs/creds/mydb-admin/af6bcdaf-b20e-4927-6eff-c5c93aef3e2e"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"lease_duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"renewable"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A1a-0684tz5r1zpz3vys"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"username"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"v-token-mydb-adm-29r3ryxwxs3ryrvy9010-1528801793"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"warnings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, this gives you a username and password that you could use to login to your postgres instance. This is a temporary credential that will expire after a default of 5 minutes. &lt;/p&gt;

&lt;p&gt;We take that &lt;code&gt;VAULT_SETTINGS&lt;/code&gt; then (using Docker of course!) we extract the username from that JSON Object using the &lt;code&gt;jq&lt;/code&gt; command. Notice how you can pipe data into a docker container. This makes docker an extremely useful tool in your toolkit because you can now use it like you would use it for normal Linux commands and create a nice data pipeline.&lt;/p&gt;

&lt;p&gt;From there we then login with that username, and we can verify that by running &lt;code&gt;\c&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So there you have it, a vault and postgres development workspace. I have the code over on &lt;a href="https://github.com/baens/docker-vault-postgres-dev-workspace"&gt;github&lt;/a&gt; if you just want to download it and use it as you need it.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>vault</category>
      <category>postgres</category>
    </item>
    <item>
      <title>Adding tests to Kotlin &amp; JAX-RS (Jersey) project</title>
      <dc:creator>Erik Lindblom</dc:creator>
      <pubDate>Mon, 28 May 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/baens/adding-tests-to-kotlin--jax-rs-jersey-project-1ail</link>
      <guid>https://dev.to/baens/adding-tests-to-kotlin--jax-rs-jersey-project-1ail</guid>
      <description>&lt;p&gt;&lt;em&gt;This entry was originally published on my blog at &lt;a href="https://blog.baens.net/posts/add-tests-to-jaxrs-setup/"&gt;blog.baens.net&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;I have a &lt;a href="https://blog.baens.net/posts/step-by-step-kotlin-jaxrs-hello-world/"&gt;blog post&lt;/a&gt; about setting up a JAX-RS with Kotlin and one thing I neglected to show was how to test. So, let's go back and fix this. For this, I will be using &lt;a href="https://junit.org/junit5/"&gt;JUnit 5&lt;/a&gt; for the test runner, &lt;a href="http://joel-costigliola.github.io/assertj/"&gt;AssertJ&lt;/a&gt; as the assertion library, and &lt;a href="http://site.mockito.org/"&gt;Mockito&lt;/a&gt; as the mocking framework.&lt;/p&gt;

&lt;p&gt;Let's go over quickly what tests I've found valuable as I've created JAX-RS services. Well, in reality, there's only two: one that exercises the HTTP interface (so, "integration test") and one that tests the class and methods in isolation (so, "unit tests"). I find it more valuable to tell which parts of the system are being exercised in the tests rather than trying to identify what type of common test level they are at. Just a weird quirk, as you will see I have plenty of them. &lt;/p&gt;

&lt;h1&gt;
  
  
  Setting up the dependencies in gradle
&lt;/h1&gt;

&lt;p&gt;First, we need to make sure we are on gradle 4.6 or greater. I personally use the wrapper version, but just verify that you have it somehow. To get that specific wrapper version, you can run &lt;code&gt;gradle wrapper --gradle-version 4.6&lt;/code&gt; and then all things should be good there.&lt;/p&gt;

&lt;p&gt;For the actual code dependencies, here is what you will need in the &lt;code&gt;build.gradle&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;junitVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"5.1.0"&lt;/span&gt;

&lt;span class="k"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// junit dependencies&lt;/span&gt;
    &lt;span class="n"&gt;testCompile&lt;/span&gt; &lt;span class="s2"&gt;"org.junit.jupiter:junit-jupiter-api:${junitVersion}"&lt;/span&gt;
    &lt;span class="n"&gt;testRuntime&lt;/span&gt; &lt;span class="s2"&gt;"org.junit.vintage:junit-vintage-engine:${junitVersion}"&lt;/span&gt;
    &lt;span class="n"&gt;testRuntime&lt;/span&gt; &lt;span class="s2"&gt;"org.junit.jupiter:junit-jupiter-engine:${junitVersion}"&lt;/span&gt;

    &lt;span class="c1"&gt;// jersey test dependencies for HTTP testing&lt;/span&gt;
    &lt;span class="n"&gt;testCompile&lt;/span&gt; &lt;span class="s2"&gt;"org.glassfish.jersey.test-framework.providers:jersey-test-framework-provider-grizzly2:${jerseyVersion}"&lt;/span&gt;

    &lt;span class="c1"&gt;// assertJ&lt;/span&gt;
    &lt;span class="n"&gt;testCompile&lt;/span&gt; &lt;span class="s1"&gt;'org.assertj:assertj-core:3.10.0'&lt;/span&gt;

    &lt;span class="c1"&gt;// mockito&lt;/span&gt;
    &lt;span class="n"&gt;testCompile&lt;/span&gt; &lt;span class="s1"&gt;'org.mockito:mockito-core:2.18.3'&lt;/span&gt;
    &lt;span class="n"&gt;testCompile&lt;/span&gt; &lt;span class="s1"&gt;'org.mockito:mockito-junit-jupiter:2.18.3'&lt;/span&gt;
    &lt;span class="n"&gt;testCompile&lt;/span&gt; &lt;span class="s1"&gt;'com.nhaarman:mockito-kotlin:1.5.0'&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Kind of messy isn't it? So a note on some of these. Any of the &lt;code&gt;org.junit&lt;/code&gt; ones are the core JUnit libraries you include for JUnit 5. We've include the &lt;code&gt;junit-vintage-engine&lt;/code&gt; because for our tests which exercise the HTTP tests are still based upon the older JUnit 4 tests from the &lt;code&gt;jersey-test-framework-provider&lt;/code&gt;. We will get into that more later. &lt;/p&gt;

&lt;p&gt;I've included &lt;a href="http://joel-costigliola.github.io/assertj/"&gt;AssertJ&lt;/a&gt; as the assertion library because I like the syntax better than the out of the box JUnit 5 style. &lt;/p&gt;

&lt;p&gt;&lt;a href="http://site.mockito.org/"&gt;Mockito&lt;/a&gt; is the mocking framework, along with a few nice to have from &lt;code&gt;mockito-kotlin&lt;/code&gt; that turn the &lt;code&gt;any()&lt;/code&gt; option into an actual instance instead of a &lt;code&gt;null&lt;/code&gt; object. And &lt;code&gt;mockito-junit-jupiter&lt;/code&gt; which allows us to run Mockito with JUnit 5. &lt;/p&gt;

&lt;h1&gt;
  
  
  Setting up the structure
&lt;/h1&gt;

&lt;p&gt;First, let's do a little bit of work to setup the inversion of control system that is used the JAX-RS version I used (Jersey), which happens to be H2. We are going to create a place we can inject bindings and determine if these are test bindings, or if they are production bindings. This gives us a layer of control of which systems to use and makes it easier for testing.  &lt;/p&gt;

&lt;p&gt;A basic binding implementation for H2 looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Bindings&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AbstractBinder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// bind(&amp;lt;implementation class&amp;gt;).to(&amp;lt;interface&amp;gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where we will house all of our bindings inside of that &lt;code&gt;configure&lt;/code&gt; method. We will get into more of what that looks like a little bit later.&lt;/p&gt;

&lt;p&gt;Now, let's actually get something useful. Let's create an interface that will hand back a list of data. So, something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;HelloJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;prop1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;prop2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;DataService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;HelloJson&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Nothing fancy, just a method that would give us back a list of data objects. &lt;/p&gt;

&lt;h1&gt;
  
  
  Notes on how to make IntelliJ work with this
&lt;/h1&gt;

&lt;p&gt;So, IntelliJ doesn't like the source along side the tests files. And honestly, I've found that to be a much better project structure in every language I'ved used. So, to make this work (though very kludgy) here is the special stuff you need to add to the &lt;code&gt;build.gradle&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nl"&gt;plugin:&lt;/span&gt; &lt;span class="s1"&gt;'idea'&lt;/span&gt;

&lt;span class="c1"&gt;// This is here to fix the intellij's issues with&lt;/span&gt;
&lt;span class="c1"&gt;// the complicated source mappings. Use the 'idea' job&lt;/span&gt;
&lt;span class="c1"&gt;// to generate a intellij project&lt;/span&gt;
&lt;span class="c1"&gt;// Ticket to make this just work out of the box: https://youtrack.jetbrains.com/issue/IDEA-188436&lt;/span&gt;
&lt;span class="n"&gt;idea&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;scopes&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;COMPILE&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;plus&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="n"&gt;configurations&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;testCompile&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is intended only for IntelliJ. I will try and test Eclipse here soon and report back but I've honestly haven't touched that in years. &lt;/p&gt;

&lt;h1&gt;
  
  
  HTTP Tests
&lt;/h1&gt;

&lt;p&gt;One of the very first tests I write when creating end points is that I can get a 200 back from the end point and get JSON back as the content-type. These tests will be my happy path test, so it should always pass. As requirements grow for this end point I will go back and add things that may be required to make this test pass by default. This is what these tests may look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;`HTTP&lt;/span&gt; &lt;span class="nc"&gt;HelloWorldResource&lt;/span&gt; &lt;span class="n"&gt;should`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JerseyTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;`returns&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;statusCode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"helloWorld"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;
        &lt;span class="nf"&gt;assertThat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;statusCode&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;isEqualTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;`returns&lt;/span&gt; &lt;span class="nc"&gt;JSON&lt;/span&gt; &lt;span class="nf"&gt;type`&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;mediaType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;target&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"helloWorld"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;request&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;mediaType&lt;/span&gt;
        &lt;span class="nf"&gt;assertThat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mediaType&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;isEqualTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MediaType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;APPLICATION_JSON_TYPE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/em&gt;: that &lt;code&gt;@Test&lt;/code&gt; annotation is from the JUnit 4 namepsace, the import looks like this: &lt;code&gt;import org.junit.Test&lt;/code&gt;. If you don't have this and instead use the newer JUnit 5 namespace, the test will not run. That is because the &lt;code&gt;JerseyTest&lt;/code&gt; base class assumes that certain things run that JUnit 5 doesn't do anymore (think static class setup process and such). You can be really neat and rename the JUnit 4 import like this: &lt;code&gt;import org.junit.Test as TestV4&lt;/code&gt; to avoid confusion if you put these types of tests in the same file. &lt;/p&gt;

&lt;p&gt;As you can see, this test isn't that horrible. It is fairly straight forward and the boilerplate around the test isn't bad. Let's go into a more complicated example with bindings.&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting up a null binding as your first implementation
&lt;/h1&gt;

&lt;p&gt;When I start adding layers to my application, I usually start with drilling down from my "upper" layers to the "lower" layers. Because of that I usually don't have an implementation per say to use for testing or for anything much else. I kind of like this approach because I can test out the API to see if I indeed want this abstraction and what kind of behavior I expect. With all of that in mind, usually when I create an interface I will always have a &lt;em&gt;null object&lt;/em&gt; right along side it. This will make it easier to start off with some default behavior and makes it easier to test the system down the road. &lt;/p&gt;

&lt;p&gt;For example, a the null object for the &lt;code&gt;DataService&lt;/code&gt; defined above may look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;NullDataService&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;DataService&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;HelloJson&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;emptyList&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Method level testing
&lt;/h1&gt;

&lt;p&gt;Now that we have our interface and it's null object, let's say we need to add functionality to our &lt;code&gt;helloWorld&lt;/code&gt; method so that it returns the data from this service. With a TDD approach, the first test maybe will just check that the method returns the same number of items. The next test may ensure that we actually have an item contained in the returning list. These tests are fairly straight forward so let's look at the code for it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ExtendWith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;MockitoExtension&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;`HelloWorldResource&lt;/span&gt; &lt;span class="nc"&gt;Should`&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;createHelloJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prop1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prop2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HelloJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prop1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;prop2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nd"&gt;@Mock&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;mockDataService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;DataService&lt;/span&gt;

    &lt;span class="nd"&gt;@InjectMocks&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;helloWorldResource&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;HelloWorldResource&lt;/span&gt;


    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;`returns&lt;/span&gt; &lt;span class="n"&gt;same&lt;/span&gt; &lt;span class="n"&gt;number&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;elements&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nc"&gt;DataService`&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;whenever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockDataService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;thenReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;createHelloJson&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nf"&gt;createHelloJson&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;

        &lt;span class="nf"&gt;assertThat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;helloWorldResource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;helloWorld&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;hasSize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nd"&gt;@Test&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;`contains&lt;/span&gt; &lt;span class="n"&gt;item&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt; &lt;span class="n"&gt;returned&lt;/span&gt; &lt;span class="nf"&gt;list`&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;expectedObject&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createHelloJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prop1&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="nf"&gt;whenever&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mockDataService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;all&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;thenReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;listOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectedObject&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="nf"&gt;assertThat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;helloWorldResource&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;helloWorld&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;expectedObject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Few things to point out here. I am using the &lt;code&gt;MockitoExtension&lt;/code&gt; that allows us to reduce on the setup parts of the tests. This allows us to create properties with the &lt;code&gt;@Mock&lt;/code&gt; and &lt;code&gt;@InjectMocks&lt;/code&gt; annotations. This makes reuse in the test class VERY easy. The &lt;code&gt;lateinit&lt;/code&gt; part is because Kotlin really wants classes to show when they will be initialized. This statement flags to the compiler that we will be doing it behind the scenes later and not to worry about things. &lt;/p&gt;

&lt;p&gt;I've also added a helper method to make creating test data easier. As you see at the top, we have a &lt;code&gt;createHelloJson&lt;/code&gt; function that creates the data object. Then if we want to override different properties, we can easily (as demonstrated in the 2nd test) add just the property we want to override. This allows the objects to have sane defaults, and if that object grows, makes it easy to add more fields without having to change 30 tests.&lt;/p&gt;

&lt;h1&gt;
  
  
  Making the HTTP tests work after we add the DataService constructor dependency
&lt;/h1&gt;

&lt;p&gt;Now, if you are following along you will notice that the above two tests work just fine, but if you run the HTTP test now, things break. That's because we now require the &lt;code&gt;DataService&lt;/code&gt; to be injected at runtime from H2. To fix that we need to make sure we have our bindings correct, so here is what the test binding and injection will look like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// in our Application.kt file&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestBindings&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AbstractBinder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;configure&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;NullDataService&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;DataService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;java&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// in our HelloWorldResource.kt file&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloWorldResource&lt;/span&gt;
&lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;dataService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;DataService&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// in our HelloWorldResource.tests.kt file&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;`HTTP&lt;/span&gt; &lt;span class="nc"&gt;HelloWorldResource&lt;/span&gt; &lt;span class="n"&gt;should`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;JerseyTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;TestBindings&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;First we needed to add the &lt;code&gt;@Inject&lt;/code&gt; property to the constructor of our resource. This will signal to Jersey that this constructor will need outside dependencies and to use H2 to find them. Our dependency is defined in our &lt;code&gt;TestBindings&lt;/code&gt; class, with the &lt;code&gt;NullDataService&lt;/code&gt; as our default. Then we add that test binding to our &lt;code&gt;JerseyTest&lt;/code&gt; creation making this all work.&lt;/p&gt;

&lt;h1&gt;
  
  
  Wrapping up
&lt;/h1&gt;

&lt;p&gt;Now, if any of this didn't make sense and you want to see it all put together, go over to the &lt;a href="https://github.com/baens/kotlin-jax-rs-helloworld-with-testing"&gt;github repository&lt;/a&gt; where this is housed and you should be able to take a look at the full thing working. I've created a static list implementation of that data service for one to look at what an actual implementation may look like. &lt;/p&gt;

&lt;h1&gt;
  
  
  Bonus: How to log exceptions in Jersey
&lt;/h1&gt;

&lt;p&gt;If you check out the code on github, you will notice another class way down in the &lt;code&gt;Application.kt&lt;/code&gt; file. This class hooks into Jersey's event system so if a request errors out in an exception, we can observe it. Take note this is just for observing if an exception has happened, not actually doing anything with the request. If we wanted to handle that, we could create a request mapper, but that is outside of the scope of this particular blog post.   &lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>testing</category>
      <category>jersey</category>
    </item>
    <item>
      <title>Notes from experimenting with GraphQL and Kotlin</title>
      <dc:creator>Erik Lindblom</dc:creator>
      <pubDate>Thu, 22 Mar 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/baens/notes-from-experimenting-with-graphql-and-kotlin-k8</link>
      <guid>https://dev.to/baens/notes-from-experimenting-with-graphql-and-kotlin-k8</guid>
      <description>&lt;p&gt;&lt;em&gt;This entry was originally published on my blog at &lt;a href="https://blog.baens.net/posts/experiment-notes-graphql-postgres/"&gt;blog.baens.net&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  What is this GraphQL thing
&lt;/h1&gt;

&lt;p&gt;I have finally got time to try out GraphQL. I've been reading about it more and more and wanted to get a sense of how to build a data API with it. Now, if you don't know what GraphQL is, here is my take on it. It is a way to create data APIs that allow clients to tell you what data they actually need. Instead of you trying to design up front all of your use cases and force clients to use that. You let them tell you what data they need, when they need it. This makes it so you as the data designer just expose the data that you have and expose ways to filter the data and the relationships that are inside the data. You don't care how the client uses it, you just expose the data as you have it. I believe this is how a data API should be designed. This decouples the why from the how which usually empowers users of the API and makes it more useful longer term.&lt;/p&gt;

&lt;h1&gt;
  
  
  Getting started with GraphQL on Kotlin
&lt;/h1&gt;

&lt;p&gt;My first approach was to create a Jersey web application that exposed the correct end points for GraphQL. Apparently, this is the wrong approach. The library I've found (&lt;a href="https://github.com/graphql-java/graphql-java"&gt;graphql-java&lt;/a&gt;) doesn't work that way. It works by adding a servlet directly to the server. Sorry if that is totally greek. Let's just say I was taking the approach of trying to build out a REST end point that just happens to have some GraphQL functionality. This was the wrong approach and what I needed to do was actually just add an HTTP route to a bit of logic and the libraries handle everything for me.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://www.howtographql.com/graphql-java/0-introduction/"&gt;"How to GraphQL with Java"&lt;/a&gt; tutorials were extremely helpful. This showed me how to wire up the library correctly and it gave me enough snipplets to figure out what needed to go where. So let's get started.&lt;/p&gt;

&lt;h1&gt;
  
  
  Server Configuration
&lt;/h1&gt;

&lt;p&gt;So for my approach I wanted to try and use the &lt;a href="https://javaee.github.io/grizzly/"&gt;embeddded Grizzly Java server&lt;/a&gt; because that is what I've been using lately as a server inside of my JVM projects. This made things a little bit more complicated because it was intended to be used as a JAX-RS server. Which meant that all the information currently out there has information on how to set that up. But for this particular case I actually needed a servlet. This was definitely going off the well beaten path. A few posts later and some tinkering it does work. &lt;/p&gt;

&lt;p&gt;The first part I figured out was getting the GraphQL schema parsed. This file, which is embedded inside of the application, needs to be parsed out to figure out what data you have. Along with that, you then provide a &lt;a href="https://github.com/graphql-java/graphql-java-tools#root-resolvers"&gt;root resolver&lt;/a&gt; that will contain the logic of how a request is intercepted and executed. This looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Setting up graphql schema, servlet, and bindings to server&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;graphqlSchema&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SchemaParser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;newParser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"schema.graphqls"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resolvers&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Query&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="c1"&gt;// we can add any number of resolvers here&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;makeExecutableSchema&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;OK, that is fairly straight forward. Now we are going to take that schema and create a servlet that we can add to our server. This looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;graphqlServlet&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;SimpleGraphQLServlet&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;graphqlSchema&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That isn't rocket science either. However, the next part is what took me the longest. For Grizzly, there is a not well documented class that helps you setup servlets. The &lt;a href="http://atetric.com/atetric/javadoc/org.glassfish.grizzly/grizzly-http-servlet-server/2.4.3/org/glassfish/grizzly/servlet/WebappContext.html"&gt;WebAppContext&lt;/a&gt; was the magical find and it really isn't well documented out there unless you look through Java source code (...yuck!...). This class sets up the servlet with all of the things it needs to run (context and bindings if you know servlets). I was hoping for something that just required a few annotations here and there but Grizzly doesn't support that (or at least I couldn't get it working). If you follow along the GraphQL how to, they setup a servlet using that annotation magic. But here, we have to do a little bit more work ourselves. This is how it ended up looking:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;webappContext&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;WebappContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Graphql Context"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;webappContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addServlet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GraphQL Endpoint"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;graphqlServlet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addMapping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/graphql"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;server&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;HttpServer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createSimpleServer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="n"&gt;webappContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;deploy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've included the server portion as well because you have to "deploy" the webapp context to a server. For these few lines it took a surprising amount of work to get it there. But in the end I like it. It is a straight forward setup that anyone could follow along if they need too.&lt;/p&gt;

&lt;p&gt;Now the next thing I wanted is to provide an interface that will allow users to play with the API. This is like the &lt;a href="https://swagger.io"&gt;swagger&lt;/a&gt; interface people are familiar with for REST end points. For GraphQL the interface usually used is &lt;a href="https://github.com/graphql/graphiql"&gt;GraphiQL&lt;/a&gt;. To setup GraphiQL is relatively easy. You copy the &lt;code&gt;index.html&lt;/code&gt; file from their github repository, place it in your code base. Tweak the file to point to a CDN, and bam. Done.  But, to get the Grizzly server to serve up that file took a little bit of coxing. Again, you need to add a servlet that will serve up that static HTML file correctly. This actually took a &lt;a href="https://stackoverflow.com/questions/20924739/grizzly-server-with-static-content-and-rest-resource"&gt;StackOverflow question&lt;/a&gt; to get me on the right path. From that it looks like I needed the &lt;code&gt;CLStaticHttpHandler&lt;/code&gt; class which looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;serverConfiguration&lt;/span&gt;
          &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addHttpHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;CLStaticHttpHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;currentThread&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;contextClassLoader&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This really isn't ground breaking but there it is. The hard part is getting the pieces together in the right order. But that's why there are blog posts. To help spread this kind of information.&lt;/p&gt;

&lt;p&gt;And that's it! We now have our server configured and ready to rock and roll.&lt;/p&gt;

&lt;h1&gt;
  
  
  Embedding the schema and html files in the JAR
&lt;/h1&gt;

&lt;p&gt;So, we have our Java code working fine, now we need to embeded those HTML files and GraphQL schema files inside our jar for the services to use. This is really straight forward but I wanted to point out that I personally don't like the default folder structure of Java projects. So I of course have to make life hard and tweak everything. Here is what I tweaked in gradle to make HTML files be in the folder &lt;code&gt;src/html&lt;/code&gt; and graphql schema files be at &lt;code&gt;src/graphql&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="k"&gt;sourceSets&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;resources&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;srcDirs&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'src/html'&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'src/graphql'&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This sets the resources directories manually (in gradle, a resource is anything that isn't code) and places them correctly in the jar file.&lt;/p&gt;

&lt;h1&gt;
  
  
  The whole shabang
&lt;/h1&gt;

&lt;p&gt;So here is the final repository if you want to see everything working: &lt;a href="https://github.com/baens/blog-experimental-graphql-servlet"&gt;https://github.com/baens/blog-experimental-graphql-servlet&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can download and fire up the server through &lt;code&gt;./gradlew run&lt;/code&gt; or even use the Docker image and use that. In the end all this does is do the same thing the how to GraphQL site does, but the pieces above are where the work was at. The resolver and repository are nothing magical at this point and follow the examples laid out everywhere else.&lt;/p&gt;

&lt;h1&gt;
  
  
  Note: magic is currently needed to make a few things work
&lt;/h1&gt;

&lt;p&gt;So, hopefully this section won't be needed much longer but I do want to point out that there is a hack to make things work. I stumbled &lt;a href="https://github.com/graphql-java/graphql-java-servlet/issues/61"&gt;upon a bug&lt;/a&gt; that would crash the GraphQL processing with this particular server. The details are a little messy, but until this issue has been resolved we need to get a custom build of the servlet library. Now this is where things are really neat. There is a service out there (how the hell do people do this for free?!) that will take any github repository and build a library for you. &lt;a href="https://jitpack.io/"&gt;Jitpack.io&lt;/a&gt; is just absolutely amazing and I want to shout out that this service is just incredible. &lt;/p&gt;

&lt;p&gt;So the magic little bits I had to sprinkle inside of gradle file were&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="k"&gt;repositories&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;maven&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="s1"&gt;'https://jitpack.io'&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;compile&lt;/span&gt; &lt;span class="s1"&gt;'com.github.briancullen:graphql-java-servlet:master-SNAPSHOT'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fairly straight forward. Point to the jitpack repository, and point to the repository that has the fix in it. &lt;/p&gt;

</description>
      <category>kotlin</category>
      <category>graphql</category>
      <category>learning</category>
    </item>
    <item>
      <title>Step-by-step: Kotlin, JAX-RS (Jersey), and Docker</title>
      <dc:creator>Erik Lindblom</dc:creator>
      <pubDate>Sat, 17 Feb 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/baens/step-by-step-kotlin-jax-rs-jersey-and-docker-54j9</link>
      <guid>https://dev.to/baens/step-by-step-kotlin-jax-rs-jersey-and-docker-54j9</guid>
      <description>

&lt;p&gt;&lt;em&gt;This was originally published on my &lt;a href="https://blog.baens.net/posts/step-by-step-kotlin-jaxrs-hello-world/"&gt;personal blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Hello Again and welcome to another blog post in my ongoing series on step-by-step tutorials. This one will actually build atop the last &lt;a href="https://blog.baens.net/posts/step-by-step-kotlin/"&gt;Hello Kotlin&lt;/a&gt; one and make a &lt;a href="https://en.wikipedia.org/wiki/Java_API_for_RESTful_Web_Services"&gt;JAX-RS&lt;/a&gt; web service. This particular implementation of JAX-RS will be &lt;a href="https://jersey.github.io/"&gt;Jersey&lt;/a&gt;. Jersey is actually the reference implementation from Oracle, but there are a few out there that I've honestly haven't given enough time.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/baens/blog-step-by-step-jaxrs/commit/830399adbaf4da38e03146b93cf4cfa58a03929e"&gt;Step 0: Prerequisites&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;For this one, I am going to start off with my Kotlin Hello World repository. This already has a Gradle wrapper setup, along with some basic things. I've changed &lt;code&gt;mainClassName&lt;/code&gt;  to &lt;code&gt;Server.kt&lt;/code&gt; and &lt;code&gt;archivesBaseName&lt;/code&gt; to match this projects name.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/baens/blog-step-by-step-jaxrs/commit/cb1373152bf52d7cdf5aa08489bafc327cf7912e"&gt;Step 1: Web Server&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;First step will be to get a working web server up and running. This project will be using the grizzly web server, which I recommend, as the embedded web server. It has a decent enough history of performance and from my usage it does a decent job.&lt;/p&gt;

&lt;p&gt;So let's take a look at how a quick server can be setup so we can verify we have the HTTP pipeline correct.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;src/Server.kt&lt;/strong&gt;&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.ws.rs.core.UriBuilder&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UriBuilder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fromUri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"http://0.0.0.0/"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;port&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;8080&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;httpServer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GrizzlyHttpServerFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;createHttpServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="k"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getenv&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="s"&gt;"SHUTDOWN_TYPE"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"INPUT"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Press any key to shutdown"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;readLine&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Shutting down from input"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;httpServer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shutdownNow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Runtime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getRuntime&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;addShutdownHook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Thread&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Shutting down from shutdown hook"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;httpServer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shutdownNow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

        &lt;span class="n"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Press Ctrl+C to shutdown"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;Thread&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;currentThread&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Line 6&lt;/strong&gt;: This creates a URI for the server to bind to. This particular one makes it so &lt;code&gt;http://localhost:8080&lt;/code&gt; will work. Probably overkill but that is what the Grizzly Server factory wants.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 9&lt;/strong&gt;: This creates the Grizzly Server and the 2nd parameter (&lt;code&gt;true&lt;/code&gt;) makes the server start immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lines 14 - 27&lt;/strong&gt;: Now, let me explain this because this is sort of magic. When running under Gradle (&lt;code&gt;./gradlew run&lt;/code&gt;), Gradle captures all of the input and passes it along to the application. So for example, on the command line you usually stop applications by hitting &lt;code&gt;Ctrl+C&lt;/code&gt;. This however doesn't work when you run it under Gradle because Gradle captures the signal and stops the daemon that is running the application. Sometimes, the Gradle daemon doesn't stop properly, or clean everything up and produces a mess the next go around. &lt;/p&gt;

&lt;p&gt;So my hack to fix all of this was to have a feature flag in an environment variable. When running under Gradle (hold on one sec and I'll show you how) we will just wait for input. When running under everything else (i.e. docker, &lt;code&gt;java -jar&lt;/code&gt;) we will wait for Ctrl+C or a kill signal from somewhere else. &lt;/p&gt;

&lt;p&gt;Now for the toolchain bits, we need to add the dependencies and setup the run bits to work with out shutdown hooks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;build.gradle (only parts)&lt;/strong&gt;&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="k"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;compile&lt;/span&gt; &lt;span class="s1"&gt;'org.jetbrains.kotlin:kotlin-stdlib-jre8'&lt;/span&gt;
    &lt;span class="n"&gt;compile&lt;/span&gt; &lt;span class="s2"&gt;"org.glassfish.jersey.containers:jersey-container-grizzly2-http:2.26"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="c1"&gt;// Properties for `./gradlew run`&lt;/span&gt;
&lt;span class="n"&gt;run&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;standardInput&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;in&lt;/span&gt;
    &lt;span class="n"&gt;environment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"SHUTDOWN_TYPE"&lt;/span&gt; &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"INPUT"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Line 4&lt;/strong&gt;: We add the grizzly http server and Jersey container.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 8 - 11&lt;/strong&gt;: This is how we make &lt;code&gt;./gradlew run&lt;/code&gt; work. The &lt;code&gt;standardInput&lt;/code&gt; we set to the normal &lt;code&gt;System.in&lt;/code&gt; (it defaults to an empty set which breaks things). Then we setup the environment variables with the &lt;code&gt;environment&lt;/code&gt; configuration.&lt;/p&gt;

&lt;p&gt;We need to add a way for the port to be exposed by Docker to the outside world. Since we are binding on port 8080 we need to have that exposed as well. So in the &lt;code&gt;Dockerfile&lt;/code&gt; we will add one little line before the CMD statement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dockerfile (only parts)&lt;/strong&gt;&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="n"&gt;EXPOSE&lt;/span&gt; &lt;span class="mi"&gt;8080&lt;/span&gt;

&lt;span class="n"&gt;CMD&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"java"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"-jar"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s2"&gt;"run.jar"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So verify the two ways to run the application and view &lt;code&gt;http://localhost:8080&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;First run &lt;code&gt;./gradlew run&lt;/code&gt; and if you hit any key, it will shutdown.&lt;/p&gt;

&lt;p&gt;Second run the docker command &lt;code&gt;docker build -t myserver . &amp;amp;&amp;amp; docker run -p 8080:8080 myserver&lt;/code&gt;. This you can run and then hit &lt;em&gt;Ctrl+C&lt;/em&gt; to shut it down. &lt;/p&gt;

&lt;p&gt;Quick aside on the docker command: there are two parts to it, first you build the image you want to run, then you run it. The &lt;code&gt;-t&lt;/code&gt; you pass in the build command is a tag that makes it easier to look up later. In the run part the &lt;code&gt;-p&lt;/code&gt; is the ports we will bind to the host. For this example we are taking the containers's 8080 port mapping it to the hosts 8080 port. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/baens/blog-step-by-step-jaxrs/commit/c281332c897fa4bb0de573d447ab3c6adebd5ee1"&gt;Step 2: Add Simple JAX-RS endpoint that prints "Hello World"&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;For this let's create the needed pipeline to get the needed resources. There is a little bit of yak shaving needed for this setup to get all of the right pieces in the place but I think I've boiled it down to the simple parts. &lt;/p&gt;

&lt;p&gt;First let's see what the resource (these are what the groups of end points are called) look like for our first end point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;src/jaxrs/resources/HelloWorld.kt&lt;/strong&gt;&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;jaxrs.resources&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.ws.rs.GET&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;javax.ws.rs.Path&lt;/span&gt;

&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"helloWorld"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HelloWorldResource&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@GET&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;helloWorld&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello World"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;There really isn't much to talk about here. The &lt;code&gt;@Path&lt;/code&gt; is where the end point will be (so in this case &lt;code&gt;/helloWorld&lt;/code&gt;). This will be retrieved from a HTTP GET.&lt;/p&gt;

&lt;p&gt;Alright, the next step is to get the system setup to register these resources automatically. So let's setup the config needed for that.&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;jaxrs&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;org.glassfish.jersey.server.ResourceConfig&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ResourceConfig&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;packages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"jaxrs.resources"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Again, this is fairly straight forward. The &lt;a href="https://jersey.github.io/apidocs/latest/jersey/org/glassfish/jersey/server/ResourceConfig.html"&gt;ResourceConfig&lt;/a&gt; is where all of base application is setup. In this example. we scan the &lt;code&gt;jaxrs.resources&lt;/code&gt; namespace for any resources or other things that can register with JAX-RS. This is a specific to Jersey but it makes it easier to setup things.&lt;/p&gt;

&lt;p&gt;Alright, now that we have all of the configuration setup for JAX-RS and a resource, lets make the server recognize it. So to the &lt;code&gt;Server.kt&lt;/code&gt; file added this.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server.kt (parts)&lt;/strong&gt;&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;httpServer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GrizzlyHttpServerFactory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;createHttpServer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="k"&gt;true&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Line 12&lt;/strong&gt;: This is all you need to add. A new instance of the &lt;code&gt;Application&lt;/code&gt; class and the Grizzly server does all the rest for you.&lt;/p&gt;

&lt;p&gt;Now, one last thing, we need to add a dependency for Jersey. This one will make all of the magical dependency injection happen behind the scenes. The Jersey team have made this configurable dependency, so if you want a different type of injection system you can. The specific one implementation we will use is &lt;a href="https://javaee.github.io/hk2/"&gt;HK2&lt;/a&gt; as opposed to &lt;a href="https://github.com/google/guice"&gt;Guice&lt;/a&gt; or others. This was just the default that I've used and have had no problems with it so I recommend it. So here is the line that needs to be added.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;build.gradle (parts)&lt;/strong&gt;&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="k"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;compile&lt;/span&gt; &lt;span class="s1"&gt;'org.jetbrains.kotlin:kotlin-stdlib-jre8'&lt;/span&gt;
    &lt;span class="n"&gt;compile&lt;/span&gt; &lt;span class="s2"&gt;"org.glassfish.jersey.containers:jersey-container-grizzly2-http:2.26"&lt;/span&gt;
    &lt;span class="n"&gt;compile&lt;/span&gt; &lt;span class="s2"&gt;"org.glassfish.jersey.inject:jersey-hk2:2.26"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Go ahead and run to see the output on &lt;code&gt;http://localhost:8080/helloWorld&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/baens/blog-step-by-step-jaxrs/commit/173f0916dbea62ca4f5ed982bf7bdaf062af58fb"&gt;Step 3: Add JSON handling&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Now that we have a simple web server up, let's get JSON handling. This isn't configured out of the box but it is straight forward. So let's get it setup and working and have an end point setup to demonstrate that.&lt;/p&gt;

&lt;p&gt;Let's setup our resource to have the parts needed to show JSON output.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;src/jaxrs/resources/HelloWorld.kt&lt;/strong&gt;&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@GET&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;helloWorld&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello World"&lt;/span&gt;

&lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;HelloJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;prop1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;prop2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@GET&lt;/span&gt;
&lt;span class="nd"&gt;@Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Produces&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MediaType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;APPLICATION_JSON&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;helloJson&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HelloJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Line 13&lt;/strong&gt;: This is why I love Kotlin, this is a data class. A  beautifully pure and simple structure to pass data around. We have two properties that will be exposed to the JSON interface. One an integer, the next a string.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lines 15-18&lt;/strong&gt;: This is how you setup an endpoint that will produce a JSON object (well, force it too, but that's for another day, or go read the &lt;a href="https://jersey.github.io/documentation/latest/jaxrs-resources.html"&gt;Jersey documentation&lt;/a&gt;). We simply just return an instance of the &lt;code&gt;HelloJson&lt;/code&gt; data class.&lt;/p&gt;

&lt;p&gt;Now, we need to tweak our dependencies and add the JSON handling. While we do this, we will also be violating the &lt;a href="https://en.wikipedia.org/wiki/Rule_of_three_(computer_programming)"&gt;Rule of 3&lt;/a&gt;, and we are going to refactor out the common things that may change. Let's see the result and we will talk about what exactly that means. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;build.gradle (parts)&lt;/strong&gt;&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="kt"&gt;def&lt;/span&gt; &lt;span class="n"&gt;jerseyVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;"2.26"&lt;/span&gt;

&lt;span class="k"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;compile&lt;/span&gt; &lt;span class="s1"&gt;'org.jetbrains.kotlin:kotlin-stdlib-jre8'&lt;/span&gt;
    &lt;span class="n"&gt;compile&lt;/span&gt; &lt;span class="s2"&gt;"org.glassfish.jersey.containers:jersey-container-grizzly2-http:${jerseyVersion}"&lt;/span&gt;
    &lt;span class="n"&gt;compile&lt;/span&gt; &lt;span class="s2"&gt;"org.glassfish.jersey.inject:jersey-hk2:${jerseyVersion}"&lt;/span&gt;
    &lt;span class="n"&gt;compile&lt;/span&gt; &lt;span class="s2"&gt;"org.glassfish.jersey.media:jersey-media-json-jackson:${jerseyVersion}"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Line 22&lt;/strong&gt;: We added this line because the parts that could change between all of these jersey dependencies is the Jersey version. So let's do the work now to make it so we can make the version change in one place. A small application of the Rule of 3, but hey, it works.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 28&lt;/strong&gt;: This is adding &lt;a href="https://github.com/FasterXML/jackson"&gt;Jackson&lt;/a&gt; to do our JSON processing. This is the magic dependency that we will need to make this all work. &lt;/p&gt;

&lt;p&gt;At this point you can now run it and hit &lt;code&gt;http://localhost:8080/helloWorld/json&lt;/code&gt; and you should see JSON output.&lt;/p&gt;

&lt;p&gt;And with that, you should now have the basics to be dangerous with. You can setup a HTTP REST server and go to town with what ever you need. But hey, let me throw in one more little bonus step that may help you out.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/baens/blog-step-by-step-jaxrs/commit/7c753f0d1ee6d474a2801a805a20fa7fa4db98e6"&gt;Bonus Step 4: Add verbose logging&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Just to make it easier to see requests coming in and out of your service on the command line. Which can help with proving you are either insane or sane depending on the circumstances, let's add a logger that will output each request.&lt;/p&gt;

&lt;p&gt;Thankfully this fairly straight forward. We just need to tweak the &lt;code&gt;Application.kt&lt;/code&gt; setup. So here is what you need.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;src/jaxrs/Application.kt&lt;/strong&gt;&lt;/p&gt;



&lt;div class="highlight"&gt;&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LoggingFeature&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Logger&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;getLogger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LoggingFeature&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DEFAULT_LOGGER_NAME&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;Level&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;INFO&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;LoggingFeature&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Verbosity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PAYLOAD_ANY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;Integer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MAX_VALUE&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;These are the lines you need to add to the &lt;code&gt;init&lt;/code&gt; block. Fairly straight forward (make sure to add all of the right &lt;code&gt;import&lt;/code&gt; statements!). This should now display all of the requests and responses on the command line so you can verify things are going in and out as expected. &lt;/p&gt;


</description>
      <category>docker</category>
      <category>kotlin</category>
      <category>jaxrs</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Step-by-step: Kotlin and Docker</title>
      <dc:creator>Erik Lindblom</dc:creator>
      <pubDate>Sun, 11 Feb 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/baens/step-by-step-kotlin-and-docker-2iok</link>
      <guid>https://dev.to/baens/step-by-step-kotlin-and-docker-2iok</guid>
      <description>&lt;p&gt;&lt;em&gt;This was originally published on &lt;a href="https://blog.baens.net/posts/step-by-step-kotlin/" rel="noopener noreferrer"&gt;my personal blog&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This is a step-by-step guide on how to get Kotlin running inside of a Docker container. We will get a basic Kotlin project running locally then demonstrate how to get that same project being built inside and running inside of a Docker container.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/baens/blog-step-by-step-kotlin" rel="noopener noreferrer"&gt;The companion repository is here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 0: Prerequisites
&lt;/h2&gt;

&lt;p&gt;I am going to assume you have the following installed and already running. We will be using the local gradle wrapper instance after the initial setup, but you do need it for the initial creation.&lt;/p&gt;

&lt;p&gt;The other one I am going to assume is having a running docker instance. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Java (JDK 1.8.0_144)&lt;/li&gt;
&lt;li&gt;Gradle (to create the initial wrapper)&lt;/li&gt;
&lt;li&gt;Docker (17.12.0-ce-mac49 (21995))&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/baens/blog-step-by-step-kotlin/commit/6ed247244a23eae991693b4a512cda2521892c9c" rel="noopener noreferrer"&gt;Step 1: Gradle&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The goal of this step will be to get a gradle wrapper up and running so that we can lock in the gradle version for everyone that will be using this repository. &lt;/p&gt;

&lt;p&gt;Run the following:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;gt; gradle wrapper --gradle-version 4.5&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Verify it works by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; ./gradlew -v

------------------------------------------------------------
Gradle 4.5
------------------------------------------------------------

Build time:   2018-01-24 17:04:52 UTC
Revision:     77d0ec90636f43669dc794ca17ef80dd65457bec

Groovy:       2.4.12
Ant:          Apache Ant(TM) version 1.9.9 compiled on February 2 2017
JVM:          1.8.0_144 (Oracle Corporation 25.144-b01)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's it! You can double check that commit that I have associated with this step to see what I add to a git repository for this but this really is an easy step. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/baens/blog-step-by-step-kotlin/commit/46304a14b7d74554775695ed3edc91a1d197e3e7" rel="noopener noreferrer"&gt;Step 2: Kotlin Hello World locally&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Our end goal for this step will be to make it print "Hello World" from the &lt;code&gt;./gradlew run&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;Let's first setup our tool chain. This will be just a gradle file with all of the plugins and dependencies that we will need. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;build.gradle&lt;/strong&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * This section is for all of the plugins we need to make this work. 
 * Kotlin, the fat jar builder, and flag it 
 * as an application so `./gradlw run` will work
 */&lt;/span&gt;
&lt;span class="n"&gt;plugins&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="s1"&gt;'org.jetbrains.kotlin.jvm'&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s1"&gt;'1.2.21'&lt;/span&gt;
    &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="s1"&gt;'com.github.johnrengelman.shadow'&lt;/span&gt; &lt;span class="n"&gt;version&lt;/span&gt; &lt;span class="s1"&gt;'2.0.2'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nl"&gt;plugin:&lt;/span&gt; &lt;span class="s1"&gt;'application'&lt;/span&gt;


&lt;span class="cm"&gt;/**
 * Standard dependency section for gradle. 
 * Define the kotlin standard libray for
 * Java 8.
 */&lt;/span&gt;
&lt;span class="k"&gt;repositories&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;mavenCentral&lt;/span&gt;&lt;span class="o"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;compile&lt;/span&gt; &lt;span class="s1"&gt;'org.jetbrains.kotlin:kotlin-stdlib-jre8'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="cm"&gt;/**
 * Personal preference. I hate having src/main/kotlin
 * be the root, so I change it that 'src'
 * is the root of my source directory.
 */&lt;/span&gt; 
&lt;span class="k"&gt;sourceSets&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;kotlin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;srcDirs&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="s1"&gt;'src'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Define the main startup class and jar name&lt;/span&gt;
&lt;span class="n"&gt;mainClassName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'MainKt'&lt;/span&gt;
&lt;span class="n"&gt;archivesBaseName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'step-by-step-kotlin'&lt;/span&gt;

&lt;span class="c1"&gt;// tell the jar which class to startup in.&lt;/span&gt;
&lt;span class="n"&gt;jar&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;manifest&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;attributes&lt;/span&gt; &lt;span class="s1"&gt;'Main-Class'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'MainKt'&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;   
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's go through some of those lines again and draw out whats going on.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lines 6 - 11&lt;/strong&gt;: These are just plugin lines. Gradle has a couple of ways to define plugins. One is called the &lt;code&gt;plugin DSL&lt;/code&gt; the other is called &lt;code&gt;script plugin&lt;/code&gt;. I'm not going to try and explain the difference here, please go read &lt;a href="https://docs.gradle.org/current/userguide/plugins.html" rel="noopener noreferrer"&gt;the plugins doc&lt;/a&gt; to get a better idea. One plugin to note is the &lt;code&gt;shadow&lt;/code&gt; plugin. This one is to create Fat Jars, or in other words, jars that contain every dependency that is needed to run. Instead of having to make sure things are on your classpath or some other nonsense, I can just give you this jar file, and it will run. This will make it running inside of docker easier.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 24&lt;/strong&gt;: Here we are defining the kotlin standard for Java 8. This is newer in Kotlin 1.1 and you can read about it &lt;a href="https://kotlinlang.org/docs/reference/using-gradle.html#configuring-dependencies" rel="noopener noreferrer"&gt;here&lt;/a&gt;. There are a few ways to do this, but this was specific to what was needed for Java 8. I've run into issues using the backwards compatible one and try and use the Java 8 one so that the newer features actually work &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lines 32 - 34&lt;/strong&gt;: This is entirely optional, but this is how I prefer to setup my projects. I hate the default of &lt;code&gt;src/main/java&lt;/code&gt; or something silly like that. That is 3 folders I have to navigate just to get to my source. PLUS then I have to navigate down through the folders of my namespace. Rarely do projects have to have all of these different types of languages so you can eliminate the &lt;code&gt;java&lt;/code&gt; folder at the very least. And 2nd, having to maintain a &lt;code&gt;test&lt;/code&gt; source folder and a &lt;code&gt;main&lt;/code&gt; source folder is the PITA. I much prefer to have my tests and source side by side. It just makes it easier to find my tests that are associated with each file.  Again, this is all personal choice but I've been doing this long enough to feel strongly about this one now. Give me one folder with all my source and don't make me nest things that I don't want too!&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 37&lt;/strong&gt;: This is a simple line but I did want to call out something. &lt;code&gt;MainKt&lt;/code&gt; is special because it will be the name of the file with &lt;code&gt;kt&lt;/code&gt; at the end of it. I will explain a little bit more when we get to that source. But this is a convention Kotlin has when there is just a method inside of the file. It will automatically enclose that method in a class for the JVM to use. So be careful about that &lt;code&gt;kt&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;Now for the actual, very simple, hello world code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;src/Main.kt:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello World"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I want to point out and congratulate the Kotlin team on this. If you have ever done any Java programming, you know that you always need a class per file. Kotlin has a few conventions to make certain things easier and I think this is brilliant. I love things like this that just remove the pomp and circumstance. This is especially helpful when trying to get new developers into the language. Every time I've had to teach someone Java, the &lt;code&gt;public class Whatever&lt;/code&gt; was foreign and we had to go down a rabbit hole even before we had anything running.  &lt;/p&gt;

&lt;p&gt;You should now be able to run &lt;code&gt;./gradlew run&lt;/code&gt; and see this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt;./gradlew run

&amp;gt; Task :run
Hello World


BUILD SUCCESSFUL in 5s
2 actionable tasks: 2 executed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;a href="https://github.com/baens/blog-step-by-step-kotlin/commit/8c781f7d5180ac25542fbf707e2d1746debcebc1" rel="noopener noreferrer"&gt;Step 3: Kotlin hello world inside docker&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Update as of 2018-02-15&lt;/strong&gt;: Thammachart Chinvarapon was gracious enough to point out that I was using the wrong Java docker container. I corrected this and moved it to the openjdk container. Thanks Thammachart!&lt;/p&gt;

&lt;p&gt;The next step will be to run this inside of a docker container. While this would be fairly straight forward, I want to demonstrate how to separate your build docker image from your running docker image. While this adds a little bit of complexity, this will actually be more like how you really use these kind of things.&lt;/p&gt;

&lt;p&gt;Since we have everything working, we just need to get a Dockerfile created and running.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Dockerfile&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;ARG&lt;/span&gt;&lt;span class="s"&gt; VERSION=8u151&lt;/span&gt;

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;openjdk:${VERSION}-jdk&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;BUILD&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . /src&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /src&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;./gradlew &lt;span class="nt"&gt;--no-daemon&lt;/span&gt; shadowJar

&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; openjdk:${VERSION}-jre&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=BUILD /src/build/libs/step-by-step-kotlin-all.jar /bin/runner/run.jar&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /bin/runner&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["java","-jar","run.jar"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Line 3 - 9&lt;/strong&gt;: This is the "builder" section.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Line 9 - 14&lt;/strong&gt;: This it the section that will be actually running.&lt;/p&gt;

&lt;p&gt;This is an awesome way to wrap up in one docker file how to build and create the image inside of itself, as well as run it. What I try and do is make it so you can create this docker image from nearly anywhere. This builder image includes all of the tools needed to build things out. And since we have this gradle wrapper, the toolchain is also there. &lt;/p&gt;

&lt;p&gt;The 2nd part is what is actually running. The &lt;code&gt;COPY --from=BUILD&lt;/code&gt; is the magic that we can pull from the last image (note: &lt;code&gt;BUILD&lt;/code&gt; is from line 3 &lt;code&gt;as BUILD&lt;/code&gt;). &lt;/p&gt;

&lt;p&gt;I'm not going to go too much of what exactly docker is doing but do want to point out a couple of quick things. We basically do a copy, setup what is the working directory (think &lt;code&gt;cd&lt;/code&gt; if you were using command line), then do the work or run.&lt;/p&gt;

&lt;p&gt;Run this and the image will build and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; kotlin &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; docker run kotlin
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>kotlin</category>
      <category>docker</category>
      <category>begnniner</category>
    </item>
  </channel>
</rss>
