<?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>Forem: Eddie Hale</title>
    <description>The latest articles on Forem by Eddie Hale (@eddiehale3).</description>
    <link>https://forem.com/eddiehale3</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%2F226538%2F95469b6b-493b-4fee-9554-b03778e29b66.jpg</url>
      <title>Forem: Eddie Hale</title>
      <link>https://forem.com/eddiehale3</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/eddiehale3"/>
    <language>en</language>
    <item>
      <title>My first open source contribution</title>
      <dc:creator>Eddie Hale</dc:creator>
      <pubDate>Thu, 17 Oct 2019 13:03:41 +0000</pubDate>
      <link>https://forem.com/eddiehale3/my-first-open-source-contribution-2i0h</link>
      <guid>https://forem.com/eddiehale3/my-first-open-source-contribution-2i0h</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover image credit to &lt;a href="https://unsplash.com/@yancymin"&gt;@yancymin&lt;/a&gt; on &lt;a href="https://unsplash.com/"&gt;unsplash&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For a while I've traversed GitHub and come up with excuses as to why I couldn't step in and help with a particular project. Some of the more frequent ones were: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I don't know that language well enough to be of any benefit. &lt;/li&gt;
&lt;li&gt;They already have so many smarter people working on this, how can I bring value? &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These projects are more than just code - there's documentation, refactoring, testing...everything you would find in a normal project. Yesterday I finally stepped out of that comfort zone and took the plunge to make my first contribution - to dev.to!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/nnFwGHgE4Mk5W/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/nnFwGHgE4Mk5W/giphy.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No, I don't know the project very well (it has some great docs). No, I technically didn't write any code. In fact my contribution was fixing lint errors and warnings for a particular subfolder. Sounds pretty straight forward, right? &lt;/p&gt;

&lt;p&gt;I was pretty nervous. Will it be approved? Did I do it right? I've fixed errors like this before... &lt;/p&gt;

&lt;p&gt;Then, the email dropped in my inbox. I felt like a little kid again. My PR was approved!! &lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/7eAvzJ0SBBzHy/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/7eAvzJ0SBBzHy/giphy.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It felt great to reach outside of that comfort zone and make an impact - even if my contribution was small. If someone out there reading this has been nervous to take the plunge, do it! Its rewarding and the community is happy to help.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>hacktoberfest</category>
    </item>
    <item>
      <title>Building a headless service in Kubernetes</title>
      <dc:creator>Eddie Hale</dc:creator>
      <pubDate>Tue, 10 Sep 2019 15:21:50 +0000</pubDate>
      <link>https://forem.com/eddiehale3/building-a-headless-service-in-kubernetes-3bk8</link>
      <guid>https://forem.com/eddiehale3/building-a-headless-service-in-kubernetes-3bk8</guid>
      <description>&lt;p&gt;Hello! This is my first post to dev.to and excited to be a part of this great community.&lt;/p&gt;

&lt;p&gt;A few weeks ago during the development of one of our apps we came across an issue where we needed to communicate with all associated pods instead of load-balancing. Our backend has 7 pods, all with the same image but different secrets to update databases at different locations.&lt;/p&gt;

&lt;p&gt;Instead of writing a service for each location and creating a ton of overhead with repetitive yaml files, changing the deployed service to a &lt;a href="https://kubernetes.io/docs/concepts/services-networking/service/#headless-services"&gt;headless service&lt;/a&gt; was the best way to go. &lt;/p&gt;




&lt;h3&gt;
  
  
  What is a headless service?
&lt;/h3&gt;

&lt;p&gt;A headless service is a service with a service IP but instead of load-balancing it will return the IPs of our associated Pods. This allows us to interact directly with the Pods instead of a proxy. It's as simple as specifying &lt;code&gt;None&lt;/code&gt; for &lt;code&gt;.spec.clusterIP&lt;/code&gt; and can be utilized with or without selectors - you'll see an example with selectors in a moment.&lt;/p&gt;

&lt;p&gt;Check out this sample config:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;my-headless-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;clusterIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;None&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;--&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;test-app&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;80&lt;/span&gt;
      &lt;span class="na"&gt;targetPort&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;3000&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  See it in action
&lt;/h3&gt;

&lt;p&gt;Create a deployment with five pods.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;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;api-deployment&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;api&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;5&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;api&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;api&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;api&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;eddiehale/hellonodeapi&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;3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a regular service&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;normal-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;api&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;80&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;3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And a headless service&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Service&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;headless-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;clusterIP&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;None&lt;/span&gt; &lt;span class="c1"&gt;# &amp;lt;-- Don't forget!!&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;api&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;80&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;3000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply the yaml and verify everything deployed correctly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl apply -f deployment.yaml
$ kubectl get all
NAME                                 READY   STATUS    RESTARTS   AGE
pod/api-deployment-f457fbcf6-6j8f9   1/1     Running   0          5s
pod/api-deployment-f457fbcf6-9gvbp   1/1     Running   0          5s
pod/api-deployment-f457fbcf6-kqbds   1/1     Running   0          5s
pod/api-deployment-f457fbcf6-m76l9   1/1     Running   0          5s
pod/api-deployment-f457fbcf6-qzhxw   1/1     Running   0          5s

NAME                       TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
service/headless-service   ClusterIP   None             &amp;lt;none&amp;gt;        80/TCP    5s
service/kubernetes         ClusterIP   10.96.0.1        &amp;lt;none&amp;gt;        443/TCP   45h
service/normal-service     ClusterIP   10.109.192.226   &amp;lt;none&amp;gt;        80/TCP    5s

NAME                             READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/api-deployment   5/5     5            5           5s

NAME                                       DESIRED   CURRENT   READY   AGE
replicaset.apps/api-deployment-f457fbcf6   5         5         5       5s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now that its all running, deploy a Pod and execute a few commands to test.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl run --generator=run-pod/v1 --rm utils -it --image eddiehale/utils bash
If you don't see a command prompt, try pressing enter.
root@utils:/# 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lets run &lt;code&gt;nslookup&lt;/code&gt; on each service to see what DNS entries exist. If we &lt;code&gt;nslookup normal-service&lt;/code&gt; one DNS entry and IP is returned, where &lt;code&gt;nslookup headless-service&lt;/code&gt; returns the list of associated Pod IPs with the service DNS:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root@utils:/# nslookup normal-service
Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   normal-service.default.svc.cluster.local
Address: 10.109.192.226

root@utils:/# nslookup headless-service
Server:         10.96.0.10
Address:        10.96.0.10#53

Name:   headless-service.default.svc.cluster.local
Address: 10.1.0.41
Name:   headless-service.default.svc.cluster.local
Address: 10.1.0.39
Name:   headless-service.default.svc.cluster.local
Address: 10.1.0.38
Name:   headless-service.default.svc.cluster.local
Address: 10.1.0.40
Name:   headless-service.default.svc.cluster.local
Address: 10.1.0.37
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Clean up
&lt;/h3&gt;

&lt;p&gt;Exit the utils pod:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;root@utils:/# exit
exit
Session ended, resume using 'kubectl attach utils -c utils -i -t' command when 
the pod is running
pod "utils" deleted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Delete the services and deployment&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ kubectl delete svc headless-service normal-service &amp;amp;&amp;amp; kubectl delete deployment api-deployment
service "headless-service" deleted
service "normal-service" deleted
deployment.extensions "api-deployment" deleted
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Headless-services allow us to reach each Pod directly, rather than the service acting as a load-balancer or proxy. This can have many use cases and I'd love to hear your experiences and thoughts in the comments!&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>containers</category>
    </item>
  </channel>
</rss>
