<?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: Lars </title>
    <description>The latest articles on DEV Community by Lars  (@advename).</description>
    <link>https://dev.to/advename</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%2F238675%2F7216bb02-4155-48f4-9535-137ecdbc8b10.png</url>
      <title>DEV Community: Lars </title>
      <link>https://dev.to/advename</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/advename"/>
    <language>en</language>
    <item>
      <title>Kubernetes Services and DNS for Dummies</title>
      <dc:creator>Lars </dc:creator>
      <pubDate>Thu, 02 Dec 2021 11:24:14 +0000</pubDate>
      <link>https://dev.to/advename/kubernetes-services-and-dns-for-dummies-27pj</link>
      <guid>https://dev.to/advename/kubernetes-services-and-dns-for-dummies-27pj</guid>
      <description>&lt;p&gt;In Kubernetes, Nodes, Pods and Services all have their own IP addresses.&lt;/p&gt;




&lt;p&gt;If you want to run the examples from this guide yourself, then you should create the following 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 create deployment --image=nginx nginx-app --replicas=2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It's also expected that you have basic Kubernetes, ReplicaSets and Deployment knowledge.&lt;/p&gt;




&lt;p&gt;Listing all our created pods with &lt;code&gt;kubectl get pods&lt;/code&gt;, we get&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME                        READY   STATUS    RESTARTS   AGE
nginx-app-d6ff45774-7m9zg   1/1     Running   0          10d
nginx-app-d6ff45774-xp2tt   1/1     Running   0          9d

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

&lt;/div&gt;



&lt;p&gt;Let's find the IP of one of our Pods with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl describe pod/nginx-app-d6ff45774-7m9zg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which returns&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
Name:         nginx-app-d6ff45774-7m9zg
Namespace:    default
Node:         minikube/192.168.49.2
Start Time:   Sun, 21 Nov 2021 12:09:04 +0100
Labels:       app=nginx-app
              pod-template-hash=d6ff45774
Status:       Running
IP:           172.17.0.3
IPs:
  IP:           172.17.0.3
Controlled By:  ReplicaSet/nginx-app-d6ff45774
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here, we can read that one of the two NGINX Pods has the &lt;code&gt;172.17.0.3&lt;/code&gt; IP address, and this address is only available from the inside of the cluster.&lt;/p&gt;

&lt;p&gt;The Pod IP address is dynamic, which means it will change every time it restarts or a new one is created as a replacement. For example, when a Pod crashes or is deleted and another one comes up with the help of a ReplicaSet, the new Pod has a different IP address from the terminated one. This makes the Pod IP address unstable which can result in application errors. The same goes for Nodes, if a Node dies pods die with it, and the Deployment will create new ones.&lt;/p&gt;

&lt;h3&gt;
  
  
  Services
&lt;/h3&gt;

&lt;p&gt;Services in Kubernetes is an abstraction that is used to group Pods into a single consistent endpoint. As Pods can be recreated, they can be attached to Services for stable IP addresses. When a network request is made to a Service, it selects all pods in the cluster matching the Service's selector, chooses one of them, and forwards the network request to it. This consistent endpoint is tied to the lifespan of the Service, and will not change while the Service is alive.&lt;/p&gt;

&lt;p&gt;Running the&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get services
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;returns&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.96.0.1    &amp;lt;none&amp;gt;        443/TCP   10d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a default Service created during the initialization of our cluster. Every Kubernetes cluster comes with a special Service, that provides a way for internal applications to talk to the API server. (Remember, running the &lt;code&gt;kubectl&lt;/code&gt; commands is talking to the API server).&lt;/p&gt;

&lt;h2&gt;
  
  
  Kubernetes Service Types
&lt;/h2&gt;

&lt;p&gt;There are different Service types used in Kubernetes. These Services differ by how they expose Pods internally or externally and the way they handle the traffic. The different Service types are described below.&lt;/p&gt;

&lt;h3&gt;
  
  
  ClusterIP
&lt;/h3&gt;

&lt;p&gt;ClusterIP exposes the Service on an internal IP in the cluster. This type makes the Service only reachable from within the cluster. ClusterIP is the &lt;strong&gt;default&lt;/strong&gt; Service if not specified otherwise.&lt;/p&gt;

&lt;p&gt;Let's create a ClusterIP Service exposing our Pods inside the cluster with a consistent IP address&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl expose deploy/nginx-app --port=80
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;expose&lt;/code&gt; - Creates a Service that exposes a Kubernetes resource (e.g. Pod, Deployment, ReplicasSet,...)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;deploy/nginx-app&lt;/code&gt; - Our &lt;code&gt;nginx-app&lt;/code&gt; deployment from before&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--port 80&lt;/code&gt; - The port that the service should serve on&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;One noteworthy additional flag is the &lt;code&gt;--target-port&lt;/code&gt; flag. Compared to &lt;code&gt;--port&lt;/code&gt;, &lt;code&gt;--target-port&lt;/code&gt; is the port on the container that the service should direct traffic to. If no &lt;code&gt;--target-port&lt;/code&gt; is specified, then it will default to the same value as &lt;code&gt;--port&lt;/code&gt;.&lt;br&gt;
E.g. &lt;code&gt;kubectl expose deployment my-app --port 80 --target-port 8080&lt;/code&gt; would result in service port &lt;code&gt;80&lt;/code&gt; targeting container port &lt;code&gt;8080&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Running &lt;code&gt;kubectl get services&lt;/code&gt; returns now&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
kubernetes   ClusterIP   10.96.0.1       &amp;lt;none&amp;gt;        443/TCP    105
nginx-app    ClusterIP   10.108.45.199   &amp;lt;none&amp;gt;        80/TCP     8s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our two Pods are now accessible within the cluster using the &lt;code&gt;10.108.45.199&lt;/code&gt; IP address.&lt;/p&gt;

&lt;p&gt;We can test that by running an additional Pod in our cluster, whose only purpose is to run a &lt;code&gt;curl&lt;/code&gt; command on that &lt;code&gt;IP:PORT&lt;/code&gt; address. By theory, &lt;code&gt;curl&lt;/code&gt; should return the NGINX welcome homepage HTML structure. We know that the NGINX container by default exposes a welcome website on to port 80.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;curl&lt;/strong&gt;&lt;br&gt;
cURL, which stands for client URL, is a command-line tool that developers use to transfer data to and from a server. At the most fundamental, cURL lets you talk to a server by specifying the location (in the form of a URL) and the data you want to send.&lt;br&gt;
E.g. running &lt;code&gt;curl http://example.com&lt;/code&gt; would return the HTML structure of &lt;code&gt;example.com&lt;/code&gt;. You could also get more information, such as headers,...&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To run an additional Pod in our cluster without a deployment, you can run a one time Pod with a shell:&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 -it network-shell --image=praqma/network-multitool --restart=Never sh; kubectl delete pod network-shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;kubectl run&lt;/code&gt; - Create and run a particular image in a Pod without a Deployment.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-it&lt;/code&gt; - Run the Container in the Pod in interactive mode that allows you to interact with the shell of the container.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;network-shell&lt;/code&gt; - Our temporary Pod name&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--image praqma/network-multitool&lt;/code&gt; &lt;a href="https://hub.docker.com/r/praqma/network-multitool"&gt;a minimalistic docker image&lt;/a&gt; (18 MB in size) with some network tool commands, including &lt;code&gt;curl&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sh&lt;/code&gt; - The command we want to run in interactive mode, here to access the shell in the network-shell container&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--restart=Never&lt;/code&gt; - A Pod without a deployment is created (default value = "Always" which creates a Deployment).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#run"&gt;The &lt;code&gt;--rm&lt;/code&gt; flag&lt;/a&gt;, which you may find online, does not seem to work on every system.&lt;br&gt;
Therefore, by combining the run and delete command with &lt;code&gt;;&lt;/code&gt; (e.g&lt;code&gt;kubectl run... ; kubectl&lt;/code&gt;), we create a one-time Pod with accessing its shell, and automatically remove it afterwards.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Attention&lt;/strong&gt;&lt;br&gt;
All flags after &lt;code&gt;sh&lt;/code&gt; will be passed as flags to &lt;code&gt;sh&lt;/code&gt;. Order matters.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;From within that one time Pod, you may now run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl 10.108.45.199
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which returns the Nginx welcome page HTML structure&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;title&amp;gt;Welcome to nginx!&amp;lt;/title&amp;gt;
&amp;lt;style&amp;gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  NodePort
&lt;/h3&gt;

&lt;p&gt;NodePort allows external accessibility to a Pod on a Node. It receives an external request from clients or users and maps to the ports. The NodePort range can be set manually, which must be in the range of &lt;em&gt;30000 – 32767&lt;/em&gt;, or is auto-assigned if not specified.&lt;/p&gt;

&lt;p&gt;Let's expose our Pod to the outside world:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl expose deploy/nginx-app --port=80 --name=nginx-app-np --type=NodePort
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Under the hood, when creating a NodePort, a ClusterIP is also created which establishes the connection to the Pods in the cluster. The ClusterIP is not shown as a separate Service, but NodePort connects to its ClusterIP which then connects to the pod IP.&lt;/p&gt;

&lt;p&gt;Running &lt;code&gt;kubectl get service&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME           TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)          AGE
kubernetes     ClusterIP   10.96.0.1        &amp;lt;none&amp;gt;        443/TCP          106d
nginx-app      ClusterIP   10.108.45.199    &amp;lt;none&amp;gt;        80/TCP           8s
nginx-app-np   NodePort    10.100.142.119   &amp;lt;none&amp;gt;        80:32358/TCP     2s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which returns us six columns &lt;code&gt;NAME&lt;/code&gt;, &lt;code&gt;TYPE&lt;/code&gt;, &lt;code&gt;CLUSTER-IP&lt;/code&gt;, &lt;code&gt;EXTERNAL-IP&lt;/code&gt;, &lt;code&gt;PORT(S)&lt;/code&gt; and &lt;code&gt;AGE&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We see now that we have our new NodePort Service &lt;code&gt;nginx-app-np&lt;/code&gt; with the type of &lt;code&gt;NodePort&lt;/code&gt;. But if you look closely at &lt;code&gt;nginx-app-np&lt;/code&gt;'s &lt;code&gt;CLUSTER_IP&lt;/code&gt; column, you see that it has an IP address, instead of being empty. This is the hidden ClusterIP service IP address, that was created with our NodePort service.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;PORT(S)&lt;/code&gt; value for our &lt;code&gt;nginx-app-np&lt;/code&gt; NodePort service is &lt;code&gt;80:32358&lt;/code&gt;, where &lt;code&gt;80&lt;/code&gt; is the hidden ClusterIP's port number, and &lt;code&gt;32358&lt;/code&gt; is the NodePort's external port number. The &lt;code&gt;--port&lt;/code&gt; flags sole purpose in the NodePort's creation was to specify the hidden ClusterIP's port (and also the target port on the container if not specified with &lt;code&gt;--target-port&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Now, when somebody connects from the outside of the cluster on port &lt;code&gt;32358&lt;/code&gt;, the traffic gets forwarded to the hidden ClusterIP on &lt;code&gt;10.108.45.199:80&lt;/code&gt; and finally to the Pod, which exposes its application on port 80 as well.&lt;/p&gt;

&lt;p&gt;You should be able to run the same &lt;code&gt;curl&lt;/code&gt; command from your host computer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;minikube users&lt;/strong&gt; - If you use minikube, then remember that you're running Kubernetes from a VM. This VM has an IP address on your machine, which you can retrieve with the &lt;code&gt;minikube ip&lt;/code&gt; command.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;microk8s users&lt;/strong&gt; - If you use microk8s (on Linux), then you should be able to use &lt;code&gt;localhost&lt;/code&gt; since Kubernetes is natively installed without a VM. If on Mac or Windows, you need to retrieve the VM's IP address..&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Running &lt;code&gt;minikube ip&lt;/code&gt; returns on my machine the &lt;code&gt;192.168.49.2&lt;/code&gt; IP address, which finally is my cluster IP address.&lt;/p&gt;

&lt;p&gt;Therefore, executing &lt;code&gt;curl 192.168.49.2:32358&lt;/code&gt; (or &lt;code&gt;curl localhost:32358&lt;/code&gt; for microk8s users) returns once again the NGINX welcome HTML structure &lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;title&amp;gt;Welcome to nginx!&amp;lt;/title&amp;gt;...&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The same goes for the hidden ClusterIP, created with the NodePort. Using the one time Pod again&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 -it network-shell --image=praqma/network-multitool --restart=Never sh; kubectl delete pod network-shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the ClusterIP IP address from our NodePort &lt;code&gt;nginx-app-np&lt;/code&gt; row, &lt;code&gt;10.100.142.119&lt;/code&gt;, and run the &lt;code&gt;curl&lt;/code&gt; command on port &lt;code&gt;80&lt;/code&gt;, i.e. &lt;code&gt;curl 10.100.142.119:80&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;NodePorts aren’t often ideal for public Services. They use non-standard ports, which are unsuitable for most HTTP traffic. You can use a NodePort to quickly set up a service for development use or to expose a TCP or UDP service on its own port. When serving a production environment to users, you’ll want to use LoadBalancer or Ingress.&lt;/p&gt;

&lt;h3&gt;
  
  
  LoadBalancer
&lt;/h3&gt;

&lt;p&gt;The LoadBalancer Service automatically integrates with load balancers provided by cloud services. These load balancers spread out workloads evenly across Kubernetes clusters, and then the Kubernetes cluster spreads out workloads evenly across the Nodes -&amp;gt; Pods -&amp;gt; Container instance.&lt;/p&gt;

&lt;p&gt;The advantage of using Load balancers here is that if a Cluster fails, the workload is directed to a backup server, which reduces the effect on users.&lt;/p&gt;

&lt;p&gt;Under the hood, when creating a LoadBalancer, a NodePort and ClusterIP are also created exposing creating the internal and external connections.&lt;/p&gt;

&lt;p&gt;For local development, Docker Desktop provides a built-in LoadBalancer.&lt;br&gt;
If you're on minikube or microk8s, LoadBalancers won't work and the service will just say "pending", but NodePort and ClusterIP work.&lt;/p&gt;

&lt;p&gt;A LoadBalancer service can be created by using the &lt;code&gt;--type=LoadBalancer&lt;/code&gt; flag.&lt;/p&gt;

&lt;p&gt;It is also important to note that a "Load Balancer" is not something Kubernetes provides out of the box. If you are using a cloud provider (like AWS, GKE, Digital Ocean, etc.) your Kubernetes installation is managed, and a Load Balancer is provided as part of your deal. But Load Balancers are not present in a bare metal Cluster that you provision on your own. There are workarounds provided by testing tools, like minikube. But other than that, you will need to manage external IPs' manually or deploy a 3rd party solution, like &lt;a href="https://metallb.universe.tf/"&gt;MetalLB&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  Domain Name System (DNS) in Kubernetes
&lt;/h2&gt;

&lt;p&gt;DNS translates an IP address that might be changing, with an easily rememberable name such as “example.com”. Every network has a DNS server, but Kubernetes implements their own DNS within the cluster to make connecting to containers a simple task.&lt;/p&gt;

&lt;p&gt;Before Kubernetes version 1.11, the Kubernetes DNS service was based on &lt;strong&gt;kube-dns&lt;/strong&gt;. Version 1.11 introduced &lt;strong&gt;CoreDNS&lt;/strong&gt; to address some security and stability concerns with kube-dns.&lt;/p&gt;

&lt;p&gt;Each time you deploy a new service or pod, the Kubernetes DNS sees the calls made to the Kube API and adds DNS entries for the new service or pod. Then other containers within a Kubernetes cluster can use these DNS entries to access the service or pod.&lt;/p&gt;

&lt;p&gt;It may also happen that only services, and no pod, receives a DNS entry.&lt;/p&gt;
&lt;h4&gt;
  
  
  Service
&lt;/h4&gt;

&lt;p&gt;Services get a DNS entry of the service name appended to the namespace and then appended to &lt;code&gt;svc.cluster.local&lt;/code&gt;.&lt;br&gt;
&lt;strong&gt;Syntax&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;service-name&amp;gt;.&amp;lt;namespace&amp;gt;.svc.&amp;lt;cluster-domain&amp;gt;.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we created the &lt;code&gt;nginx-app&lt;/code&gt; service, a &lt;code&gt;nginx-app.default.svc.cluster.local&lt;/code&gt; entry has been added to the Kubernetes DNS, where &lt;code&gt;initial&lt;/code&gt; is the default Kubernetes namespace. (More about namespace later). &lt;code&gt;cluster.local&lt;/code&gt; is the default cluster domain.&lt;/p&gt;

&lt;h4&gt;
  
  
  Pod
&lt;/h4&gt;

&lt;p&gt;Similarly pods get entries of pod IP address appended to the namespace and then appended to &lt;code&gt;.pod.cluster.local&lt;/code&gt;. The pod IP addresses &lt;strong&gt;dots&lt;/strong&gt; &lt;code&gt;172.12.0.3&lt;/code&gt; &lt;strong&gt;must be replaced with dashes&lt;/strong&gt; &lt;code&gt;172-12-0-3&lt;/code&gt;.&lt;br&gt;
&lt;strong&gt;Syntax&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;`&amp;lt;pod-ip-address&amp;gt;.&amp;lt;namespace&amp;gt;.pod.&amp;lt;cluster-domain&amp;gt;.local`
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When we created our &lt;code&gt;nginx-app&lt;/code&gt; deployement, one of the created pods, the &lt;code&gt;nginx-app-d6ff45774-7m9zg&lt;/code&gt;, got assigned the &lt;code&gt;172.17.0.3&lt;/code&gt; IP address. The entry &lt;code&gt;172-17-0-3.default.pod.cluster.local&lt;/code&gt; was then added to the Kubernetes DNS.&lt;/p&gt;

&lt;h4&gt;
  
  
  How to check if Pod DNS is enabled in your Cluster?
&lt;/h4&gt;

&lt;p&gt;CoreDNS has by default disabled Pod DNS in a Kubernetes Cluster, but many local Kubernetes tools (e.g. minikube) or Cloud Kubernetes services (e.g. AWS EKS) have it enabled to make it still compatible with &lt;code&gt;kube-dns&lt;/code&gt;.&lt;br&gt;
CoreDNS uses the server block syntax (same as NGINX config) for its &lt;a href="https://coredns.io/plugins/kubernetes/"&gt;configuration&lt;/a&gt;. The &lt;code&gt;pod&lt;/code&gt; property in the configuration (also known as &lt;em&gt;POD-MODE&lt;/em&gt;) determines if pod DNS is enabled or not.&lt;br&gt;
The three valid &lt;code&gt;pod&lt;/code&gt; values are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;disabled&lt;/code&gt; - Default. Do not process Pod requests, always returning &lt;code&gt;NXDOMAIN&lt;/code&gt; (domain name can't be resolved by a DNS)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;insecure&lt;/code&gt; - Default for minikube, AWS,... . Always return an A record with IP from request, even if the Pod IP address doesn't exist. This option is provided for backward compatibility with &lt;code&gt;kube-dns&lt;/code&gt;.
&lt;code&gt;verified&lt;/code&gt; - Return an A record if there exists a Pod in the same namespace with matching IP. This option requires substantially more memory than in insecure mode since it will maintain a watch on all Pods.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;code&gt;insecure&lt;/code&gt; setting is vulnerable to abuse if used maliciously in conjunction with wildcard SSL certs. Meaning, if you handle traffic with pod DNS entries, instead of Services, then you're vulnerable to DNS spoofing. But this should not be the case since we learned that you should handle traffic with Services as they have non-ephemeral IP addresses.&lt;br&gt;
DNS Spoofing (&lt;a href="https://blog.aquasec.com/dns-spoofing-kubernetes-clusters"&gt;DNS spoofing example in the bottom of this page&lt;/a&gt;) in this context means that one malicious Pod intercepts incoming traffic and returns malicious code or applications, instead of the original one. (&lt;a href="https://coredns.io/2017/03/01/coredns-for-kubernetes-service-discovery-take-2/"&gt;Source&lt;/a&gt;)&lt;br&gt;
As long as you know that every developer in a cluster handles traffic with Services and not Pods, you should not be too worried about &lt;code&gt;pod insecure&lt;/code&gt; as it's a backward compatibility for &lt;code&gt;kube-dns&lt;/code&gt; and pretty much industry standard (e.g. AWS EKS &lt;a href="https://aws.amazon.com/premiumsupport/knowledge-center/eks-conditional-forwarder-coredns/"&gt;uses &lt;code&gt;insecure&lt;/code&gt;&lt;/a&gt; ).&lt;/p&gt;

&lt;p&gt;Let's inspect our Kubernetes CoreDNS configurations&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;kubectl get -n kube-system configmaps/coredns -o yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which should return the along the lines&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;...
  kubernetes cluster.local in-addr.arpa ip6.arpa {
     pods insecure
     fallthrough in-addr.arpa ip6.arpa
     ttl 30
  }
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can see that we have Pod DNS enabled.&lt;/p&gt;

&lt;h4&gt;
  
  
  Resolving DNS entries
&lt;/h4&gt;

&lt;p&gt;The diagram below shows a pair of Services and a pair of Pods that are deployed across two different Namespaces. Below are the DNS entries that you can expect to be available for these objects, assuming Pod DNS is enabled for your cluster.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--mbhUQjqv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qo2lw7ns9k97uubmardd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--mbhUQjqv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qo2lw7ns9k97uubmardd.png" alt="Image description" width="880" height="735"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Any pods looking for a Service within the same namespace can just use the common name of the “Service” (e.g. &lt;code&gt;ninja&lt;/code&gt; service) instead of the fully qualified domain name (FQDN - is the most complete domain name that identifies a host or server)(e.g. &lt;code&gt;hollowapp.namespace1.svc.cluster.local&lt;/code&gt;). Kubernetes will add the proper DNS suffix to the request if one is not given (explained in &lt;em&gt;Kubernetes &amp;amp; Unix networking&lt;/em&gt; below).&lt;/p&gt;




&lt;p&gt;To test this with our &lt;code&gt;nginx-app&lt;/code&gt; setup, run again the command to create the one time Pod:&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 -it network-shell --image=praqma/network-multitool --restart=Never sh; kubectl delete pod network-shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We know that we currently have three Services, the ClusterIP service &lt;code&gt;nginx-app&lt;/code&gt;, the NodePort service &lt;code&gt;nginx-app-np&lt;/code&gt; and LoadBalancer service &lt;code&gt;nginx-app-lb&lt;/code&gt; (optional).&lt;/p&gt;

&lt;p&gt;In our one time Pod, run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nslookup nginx-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;code&gt;nginx-app&lt;/code&gt; is the name of our Service and &lt;code&gt;nslookup&lt;/code&gt; is a command for obtaining from DNS servers the IP address of a domain name and vice-versa.&lt;/p&gt;

&lt;p&gt;The results show the ClusterIP address of the Service. Also, pay close attention to the FQDN, which follows the service DNS syntax that we've previously seen.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ nslookup nginx-app
Server:     10.96.0.10
Address:    10.96.0.10#53

Name:   nginx-app.default.svc.cluster.local
Address: 10.111.70.23
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Kubernetes &amp;amp; Unix networking
&lt;/h2&gt;

&lt;p&gt;The following section explains some basics of unix networking which helps to further understand Kubernetes DNS and Services.&lt;br&gt;
We will look at &lt;code&gt;nslookup&lt;/code&gt; and how it can resolve &lt;code&gt;nginx-app&lt;/code&gt; without the need for the fully qualified domain name.&lt;/p&gt;
&lt;h3&gt;
  
  
  The &lt;code&gt;resolv.conf&lt;/code&gt; file
&lt;/h3&gt;

&lt;p&gt;DNS resolution inside a container - like any Linux system - is driven by the &lt;code&gt;/etc/resolv.conf&lt;/code&gt; config file.&lt;/p&gt;

&lt;p&gt;You can check your local (Linux only) host machines &lt;code&gt;resolv.conf&lt;/code&gt; file with&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat /etc/resolv.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Returning&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nameserver 127.0.0.53
options edns0 trust-ad
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



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

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;nameserver&lt;/code&gt; directs to an IP address of a DNS, which in return translates domain names into IP addresses. The IP &lt;code&gt;127.0.0.53&lt;/code&gt; is a local DNS cache resolver, aka a temporary database that stores information about previous DNS lookups. Whenever you visit a website, your OS and web browser will keep a record for the domain and the corresponding IP address increasing performance instead of using a remote DNS.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;options edns0 trust-ad&lt;/code&gt; insignificant option&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But the &lt;code&gt;resolv.conf&lt;/code&gt; file has one more important part, the &lt;code&gt;search&lt;/code&gt; directive.&lt;br&gt;
Let's have a look at a more complete &lt;code&gt;resolv.conf&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;search eng.matata.com dev.matata.com fr.matata.com
options ndots:2
nameserver 10.436.22.8
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;search eng.matata.com dev.matata.com labs.matata.com&lt;/code&gt; contains a list of domain names, which each one will be appended for every domain name query. (E.g. querying for &lt;code&gt;banana&lt;/code&gt;, the search directive would search for &lt;code&gt;banana.eng.matata.com&lt;/code&gt;, &lt;code&gt;banana.dev.matata.com&lt;/code&gt;,..)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;options ndots:2&lt;/code&gt; The number of maximum allowed dots in a domain name query for using the &lt;code&gt;search&lt;/code&gt; directive, before querying a remote DNS server (e.g. &lt;code&gt;chef.example.com&lt;/code&gt; has two dots). If the number of dots surpasses the &lt;code&gt;ndots&lt;/code&gt; value, then the remote DNS server is first asked to resolve the domain name before (only if failed) to use the &lt;code&gt;search&lt;/code&gt; directive and perform a local DNS resolution.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;nameserver 10.436.22.8&lt;/code&gt; when using the search directive, forward the query to the DNS at the &lt;code&gt;10.436.22.8&lt;/code&gt; IP address about A-records, CNAME,.. .&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If a domain name can't be resolved by a DNS (aka, no A-record, CNAME,... exists) then it will return an &lt;code&gt;NXDOMAIN&lt;/code&gt; (non-existing domain) error response.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A-Record vs CNAME record&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;DNS's use records to point a domain name to an IP address.&lt;br&gt;
A-Record maps a name to one or more IP addresses. CNAME maps a domain name to another domain name.&lt;br&gt;
It's usual that an A-record is created for a root domain, e.g. &lt;code&gt;example.com -&amp;gt; 102.192.22.102&lt;/code&gt; and a CNAME record for subdomains such as &lt;code&gt;banana.example.com -&amp;gt; example.com&lt;/code&gt;. It's then up to the server to handle requests for the two domains and&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Example: Querying for &lt;code&gt;hakuna&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
Using the previous &lt;code&gt;resolv.conf&lt;/code&gt; file, imagine we know that a CNAME exists for &lt;code&gt;hakuna.dev.matata.com&lt;/code&gt; and we want to find the IP of the server.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;hakuna&lt;/code&gt; has less than &lt;code&gt;ndots:2&lt;/code&gt; dots in the domain name. so it first performs a local search.&lt;/p&gt;

&lt;p&gt;Running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nslookup hakuna
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;executes a local search in following order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;hakuna.eng.matata.com&lt;/code&gt; -&amp;gt; fails with &lt;code&gt;NXDOMAIN&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hakuna.dev.matata.com&lt;/code&gt; -&amp;gt; success and stops here, DNS returns the ClusterIP address of the Service&lt;/li&gt;
&lt;li&gt;&lt;code&gt;hakuna.labs.matata.com&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Example: Querying for &lt;code&gt;aws.amazon.com&lt;/code&gt;&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;aws.amazon.com&lt;/code&gt; has more than &lt;code&gt;ndots:2&lt;/code&gt; dots in the domain name, so it's considered as an absolute name ( = FQDN) and first resolved with a remote DNS, before resolving it locally with the &lt;code&gt;search&lt;/code&gt; directive.&lt;/p&gt;
&lt;h4&gt;
  
  
  Resolving &lt;code&gt;nginx-app&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Let's inspect the &lt;code&gt;/etc/resolv.conf&lt;/code&gt; of a with the one time Pod.&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 -it network-shell --image=praqma/network-multitool --restart=Never sh; kubectl delete pod network-shell
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the Pod, run&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cat /etc/resolv.conf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which should return&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;nameserver 10.96.0.10
search default.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here &lt;code&gt;10.96.0.10&lt;/code&gt; is our nameserver IP address, which in theory should be CoreDNS. We can investigate that nameserver IP address 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;kubectl get service -n kube-system
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;-n&lt;/code&gt; is a shorthand for &lt;code&gt;--namespace&lt;/code&gt; and allows you to specify the namespace in where to look for services&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;kube-system&lt;/code&gt; is the namespace for services, pods,... created by the Kubernetes system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That command should return&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME       TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
kube-dns   ClusterIP   10.96.0.10   &amp;lt;none&amp;gt;        53/UDP,53/TCP,9153/TCP   114d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have an IP address match! But hold up a second. Why is the Service name &lt;code&gt;kube-dns&lt;/code&gt; and not &lt;code&gt;coredns&lt;/code&gt;?&lt;br&gt;
The system nameserver Service name was kept as &lt;code&gt;kube-dns&lt;/code&gt;, even as it now uses CoreDNS under the hood for backwards compatibility from CoreDNS to &lt;code&gt;kube-dns&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;We can verify this 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;kubectl get pods -l k8s-app=kube-dns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;which returns:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME                               READY   STATUS    RESTARTS   AGE
coredns-558bd4d5db-rvvst           1/1     Running   2          114d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-l&lt;/code&gt; flag stands for &lt;code&gt;labels&lt;/code&gt; and is later on covered. But basically, the commands return the Pods which are served by the &lt;code&gt;kube-dns&lt;/code&gt; Service.&lt;/p&gt;

&lt;p&gt;Now that we understand our &lt;code&gt;10.96.0.10&lt;/code&gt; IP address, we run the &lt;code&gt;search&lt;/code&gt; directive since &lt;code&gt;nginx-app&lt;/code&gt; has fewer dots than the specification of &lt;code&gt;options ndots:5&lt;/code&gt;.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;nginx-app.default.svc.cluster.local&lt;/code&gt; -&amp;gt; success and stops here, DNS returns the ClusterIP address of the service&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nginx-app.svc.cluster.local&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;nginx-app.cluster.local&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Additional Sources:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://theithollow.com/2019/02/18/kubernetes-dns/"&gt;Kubernetes - DNS - The IT Hollow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@hsahu24/understanding-dns-resolution-and-resolv-conf-d17d1d64471c"&gt;Understanding DNS resolution and resolv.conf | by Himanshu Sahu | Medium&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pracucci.com/kubernetes-dns-resolution-ndots-options-and-why-it-may-affect-application-performances.html"&gt;Kubernetes pods /etc/resolv.conf ndots:5 option&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://kubernetes.io/docs/reference/generated/kubectl/kubectl-commands#expose"&gt;Kubectl Reference Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>kubernetes</category>
      <category>networking</category>
      <category>services</category>
    </item>
    <item>
      <title>Relational Database - How to locate candidate keys in a table</title>
      <dc:creator>Lars </dc:creator>
      <pubDate>Wed, 09 Oct 2019 08:04:02 +0000</pubDate>
      <link>https://dev.to/advename/relational-databases-how-to-locate-candidate-keys-in-a-table-2a1m</link>
      <guid>https://dev.to/advename/relational-databases-how-to-locate-candidate-keys-in-a-table-2a1m</guid>
      <description>&lt;p&gt;Finding a table's candidate key's during the database design process without having a lot or any mock up-data can be difficult sometimes. There's, however, one well known trick - but many guides use a simplified version which only works on basic tables. In this article, I want to demonstrate the correct version, which works 99% of the times.&lt;/p&gt;

&lt;p&gt;Before we start, we'll have a quick look what functional dependencies are.&lt;/p&gt;

&lt;h2&gt;
  
  
  Functional dependency
&lt;/h2&gt;

&lt;p&gt;If a value of column A is associated with one value of column B, we say:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A determines B&lt;/li&gt;
&lt;li&gt;or, B depends on A&lt;/li&gt;
&lt;li&gt;or, A -&amp;gt; B&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is called functional dependency.&lt;/p&gt;

&lt;h2&gt;
  
  
  Find the candidate key of a Songs table
&lt;/h2&gt;

&lt;p&gt;Let's locate the candidate key's of this album - artist - song table.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;album_name&lt;/th&gt;
&lt;th&gt;album_year&lt;/th&gt;
&lt;th&gt;artist_name&lt;/th&gt;
&lt;th&gt;artist_genre&lt;/th&gt;
&lt;th&gt;song_name&lt;/th&gt;
&lt;th&gt;song_duration&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;From the table above, we can tell that our dependencies are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;album_name -&amp;gt; album_year
artist_name -&amp;gt; artist_genre
song_name -&amp;gt; song_duration
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The next step is to illustrate these dependencies with a drawing.&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Mwx0c42O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1e5nu6ff4mesn92drd6q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Mwx0c42O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/1e5nu6ff4mesn92drd6q.png" alt="Locate candidate key relational database" width="584" height="424"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Based on the drawing, we can tell that we need &lt;em&gt;album_name&lt;/em&gt;, &lt;em&gt;artist_name&lt;/em&gt; and &lt;em&gt;song_name&lt;/em&gt; to get all attributes.&lt;/p&gt;

&lt;p&gt;Therefore, the candidate key of our table is: &lt;br&gt;
{album_name, artist_name, song_name}&lt;/p&gt;
&lt;h2&gt;
  
  
  Drawing method explained
&lt;/h2&gt;

&lt;p&gt;By following the arrows, we try to get to every attribute using one or multiple attributes as a starting point.&lt;br&gt;
For the example from above, we have to start from album_name, artist_name and song_name to get to every attribute.&lt;/p&gt;

&lt;p&gt;An attribute that is not connected to any other attribute signals that this attribute is already part of the candidate key.&lt;/p&gt;

&lt;p&gt;Let's try more examples.&lt;/p&gt;
&lt;h3&gt;
  
  
  Example 1
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Movie(title, year, genre, genre-description, director, director-home-country)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;If we tabulated the table above, it would look like:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Movie&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;title&lt;/th&gt;
&lt;th&gt;year&lt;/th&gt;
&lt;th&gt;genre&lt;/th&gt;
&lt;th&gt;genre_desc&lt;/th&gt;
&lt;th&gt;director&lt;/th&gt;
&lt;th&gt;director_country&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;From first view, it's impossible to determine which is the candidate key.&lt;/p&gt;

&lt;p&gt;But we do know the dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;title -&amp;gt; year
title -&amp;gt; genre
title -&amp;gt; director
genre -&amp;gt; genre-description
director -&amp;gt; director-home-country
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, let's draw the dependencies:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AUb0li09--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jg9capmosk39gbcbe5cy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AUb0li09--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/jg9capmosk39gbcbe5cy.png" alt="Locate candidate key relational database" width="842" height="342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We only need the attribute title to determine all other attributes.&lt;br&gt;
Therefore, {title} is the candidate key.&lt;/p&gt;
&lt;h3&gt;
  
  
  Example 2
&lt;/h3&gt;

&lt;p&gt;Now, let's do an example without obvious names.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;R(A, B, C, D, E, F, G)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Dependencies:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A -&amp;gt; B
B  -&amp;gt; {A, C, E}
C -&amp;gt; {B, F, D}
F -&amp;gt; {D, G}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Curly brackets are just a short hand for a group of attributes with a functional dependency to another (group) attribute.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's draw, once again, the dependencies:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pL3yXEL_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/bsimhzwjnu9d0x8w1xqt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pL3yXEL_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/bsimhzwjnu9d0x8w1xqt.png" alt="Locate candidate key relational database" width="662" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By analysing this drawing, we can get to every attribute starting from A, B and C.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Explanation with starting from C:&lt;br&gt;
C -&amp;gt; {B, F, D}&lt;br&gt;
then, B -&amp;gt; {A, C, E}&lt;br&gt;
then, F -&amp;gt; {D, G}&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We have covered all attributes only by using C.&lt;/p&gt;

&lt;p&gt;Candidate keys: {A}, {B} or {C}&lt;/p&gt;
&lt;h3&gt;
  
  
  Example 3
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;R = (A, B, C, D, E)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;strong&gt;Dependencies:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A -&amp;gt; B
{E, D} -&amp;gt; A
{B, C} -&amp;gt; E
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Drawing:&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--G5bbRiEK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kcb3o4vu64vynx8czwad.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--G5bbRiEK--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://thepracticaldev.s3.amazonaws.com/i/kcb3o4vu64vynx8czwad.png" alt="Locate candidate key relational database" width="604" height="538"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There's no arrow ever going to D and C. This signals that D and C are already a part of our candidate keys.&lt;br&gt;
However, we need to combine {D, C} with either A, B or E to get all attributes.&lt;/p&gt;

&lt;p&gt;Candidate keys: {D, C, A} or {D, C, B} or {D, C, E}&lt;/p&gt;

&lt;h3&gt;
  
  
  Source:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://www.rlvision.com/blog/method-for-determining-candidate-keys-and-highest-normal-form-of-a-relation-based-on-functional-dependencies/"&gt;https://www.rlvision.com/blog/method-for-determining-candidate-keys-and-highest-normal-form-of-a-relation-based-on-functional-dependencies/&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://stackoverflow.com/questions/21224354/finding-candidate-keys-from-given-relations"&gt;https://stackoverflow.com/questions/21224354/finding-candidate-keys-from-given-relations&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;(Simplified version) &lt;a href="https://medium.com/@stinaqv/a-beginners-guide-to-locating-the-candidate-key-and-normal-form-of-a-relation-764d14930463"&gt;https://medium.com/@stinaqv/a-beginners-guide-to-locating-the-candidate-key-and-normal-form-of-a-relation-764d14930463&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>database</category>
      <category>keys</category>
      <category>relational</category>
      <category>find</category>
    </item>
    <item>
      <title>Vocabulary guide of relational database terms</title>
      <dc:creator>Lars </dc:creator>
      <pubDate>Sun, 29 Sep 2019 12:15:17 +0000</pubDate>
      <link>https://dev.to/advename/vocabulary-guide-of-relational-database-terms-3931</link>
      <guid>https://dev.to/advename/vocabulary-guide-of-relational-database-terms-3931</guid>
      <description>&lt;p&gt;While I was learning, in more depth, the relational database using books, tutorials, guides and articles, I've quickly got confused as there is a tremendous inconsistency in the relational database terminology.&lt;/p&gt;

&lt;p&gt;Here an example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Person A: A field is the same as a column&lt;/li&gt;
&lt;li&gt;Person B: A field is an intersection between a column and a row&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This can quickly lead to confusions when the context is not clear at the beginning of the text. &lt;/p&gt;

&lt;p&gt;What is is now, records, rows, tuples, columns, attributes, fields, relations, tables, entities, cell, item, domains or data value?&lt;br&gt;
Where did this inconsistency originate from and what are the actual "correct" terms? &lt;br&gt;
That's what we will have a look at in this article.&lt;/p&gt;

&lt;h2&gt;
  
  
  History
&lt;/h2&gt;

&lt;p&gt;Before we can analyze the origination of the term's, we somehow have to understand some history pieces of data and relational database.&lt;/p&gt;

&lt;p&gt;In the old days, data was stored using a &lt;em&gt;file-based system&lt;/em&gt; &lt;sup&gt;1&lt;/sup&gt; . A company system has a number of applications programs; each of them is designated to manipulate data files (imagine files with the &lt;code&gt;.txt&lt;/code&gt; extension). Each single file contained records of data, e.g. a Client File contained records of Clients.   &lt;/p&gt;

&lt;p&gt;In 1970, E.F. Codd introduced the world to his research paper "A Relational Model of Data for Large Shared Data Banks" &lt;sup&gt;2,3&lt;/sup&gt;. In this paper and later papers, he defined what he meant by "relational". He is the inventor and father of the relational model and relational algebra &lt;sup&gt;4,5,6&lt;/sup&gt; , which is closely derived from the mathematical set theory &lt;sup&gt;7&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;In 1979, based on E.F. Codd's relational database paper, Oracle released the first commercial relational database management system (RDBMS).&lt;/p&gt;

&lt;h2&gt;
  
  
  Origination
&lt;/h2&gt;

&lt;p&gt;Based on history, we can continue with the three subjects file-based system, relational algebra, the relational database management system and will throw in web/app development.&lt;/p&gt;

&lt;p&gt;While working or operating with every single one of them, you need to use different terms.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File-based system&lt;/strong&gt;&lt;br&gt;
A group of data is stored in files. A single entry is called a record.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Relational algebra&lt;/strong&gt;&lt;br&gt;
The relational algebra uses operators from the set theory with additional constraints and allows “new” relations to be derived from “old” ones. Every relation has a&lt;br&gt;
heading and a body: The heading is a set of attributes (whereby the term attribute I mean an&lt;br&gt;
attribute-name/type-name pair), and the body is a set of tuples that conform to that&lt;br&gt;
heading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Relational database management system&lt;/strong&gt;&lt;br&gt;
A relational database management system consists of one or multiple tables. A table is a collection of related data held in a table format within a database. It consists of columns and rows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Web/app development terms&lt;/strong&gt;&lt;br&gt;
A field is an object for storing a single value/value type. Data value is a generic term that can be used in all contexts&lt;/p&gt;

&lt;h2&gt;
  
  
  Terms comparison
&lt;/h2&gt;

&lt;p&gt;As you probably have noticed, these subjects have one thing in common, processing data. However, they are different things.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oCG9EGs0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/imgBDOp.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oCG9EGs0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://i.imgur.com/imgBDOp.jpg" alt="Relational database correct terms"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://raw.githubusercontent.com/advename/Vocabulary-guide-of-relational-database-terminology/master/relational-database-terms-difference.jpg"&gt;View image in full size: Relational database correct terms , inconsistency&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Even if the valid terms are table, column and rows, educational programs, articles and many other sources are still mixing them up and that to an extent that the correctness of using them can be considered as not important. All that matters is that you communicate in a way that everyone understands. Therefore, it's important to define the terms to be used in teams to prevent confusions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sources:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://opentextbc.ca/dbdesign01/chapter/chapter-1-before-the-advent-of-database-systems/"&gt;Chapter 1 Before the Advent of Database Systems – Database Design – 2nd Edition&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Relational_database"&gt;Relational database - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Relational_algebra"&gt;Relational algebra - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dl.acm.org/citation.cfm?id=362685"&gt;A relational model of data for large shared data banks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Relational_database"&gt;Relational database - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://web.cecs.pdx.edu/~maier/TheoryBook/TRD.html"&gt;David Maier: The Theory of Relational Databases&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Set_theory"&gt;Set theory - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Additional sources and inspiration:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dba.stackexchange.com/questions/65609/column-vs-field-have-i-been-using-these-terms-incorrectly"&gt;terminology - Column vs Field: have I been using these terms incorrectly? - Database Administrators Stack Exchange&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dba.stackexchange.com/questions/31805/what-is-the-difference-between-a-record-and-a-row-in-sql-server?noredirect=1&amp;amp;lq=1"&gt;terminology - What is the difference between a "record" and a "row" in SQL Server? - Database Administrators Stack Exchange&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Relational_database"&gt;Relational database - Wikipedia&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.1keydata.com/datawarehousing/data-modeling-levels.html"&gt;Data Modeling - Conceptual, Logical, and Physical Data Models&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Joe celko - data &amp;amp; databases: concepts in practice&lt;/li&gt;
&lt;li&gt;C.J. Date - An introduction to database systems&lt;/li&gt;
&lt;li&gt;C.J. Date - The new relational database dictionary&lt;/li&gt;
&lt;li&gt;E.F. Codd - The relational model for database management&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>terms</category>
      <category>relational</category>
      <category>database</category>
      <category>inconsistency</category>
    </item>
  </channel>
</rss>
