Service types
There are four types of services:
- ClusterIP
- NodePort
- LoadBalancer
- ExternalName
LoadBalancer includes the features of NodePort and ClusterIP
ClusterIP
ClusterIP is the default service type. It exposes the service on a cluster-internal IP. Pods in the cluster could reach the service via the IP address, environment variables, or DNS.
In the following example, we'll learn how to use both native service environment variables and DNS to access the pods behind services in the cluster.
Before starting a service, we'd like to create two sets of RC shown below
# create RC 1 with nginx 1.12.0 version
cat << EOF > 3-2-3_rc1.yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx-1.12
spec:
replicas: 2
selector:
project: chapter3
service: web
version: "0.1"
template:
metadata:
name: nginx
labels:
project: chapter3
service: web
version: "0.1"
spec:
containers:
- name: nginx
image: nginx:1.12.0
ports:
- containerPort: 80
EOF
# create RC 2 with nginx 1.13.1 version
cat << EOF > 3-2-3_rc2.yaml
apiVersion: v1
kind: ReplicationController
metadata:
name: nginx-1.13
spec:
replicas: 2
selector:
project: chapter3
service: web
version: "0.2"
template:
metadata:
name: nginx
labels:
project: chapter3
service: web
version: "0.2"
spec:
containers:
- name: nginx
image: nginx:1.13.1
ports:
- containerPort: 80
EOF
Then we could make our pod selector, targeting project and service labels
# simple nginx service
cat << EOF > 3-2-3_service.yaml
kind: Service
apiVersion: v1
metadata:
name: nginx-service
spec:
selector:
project: chapter3
service: web
ports:
- protocol: TCP
port: 80
targetPort: 80
name: http
EOF
# create the RCs
kubectl create -f 3-2-3_rc1.yaml
replicationcontroller "nginx-1.12" created
kubectl create -f 3-2-3_rc2.yaml
replicationcontroller "nginx-1.13" created
# create the service
kubectl create -f 3-2-3_service.yaml
service "nginx-service" created
Check nginx-service information
kubectl describe service nginx-service
Name: nginx-service
Namespace: default
Labels: <none>
Annotations: <none>
Selector: project=chapter3,service=web
Type: ClusterIP
IP: 10.43.9.128
Port: http 80/TCP
TargetPort: 80/TCP
Endpoints: 10.42.1.3:80,10.42.2.4:80,10.42.3.3:80 + 1 more...
Session Affinity: None
Events: <none>
List current endpoints
kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 159.65.144.250:6443,159.65.156.182:6443,159.65.159.71:6443 + 2 more... 1h
nginx 10.42.2.3:80,10.42.3.2:80 8m
nginx-service 10.42.1.3:80,10.42.2.4:80,10.42.3.3:80 + 1 more... 1m
curl 10.42.1.3:80
curl 10.42.2.3:80
curl 10.42.2.4:80
curl 10.42.3.2:80
curl 10.42.3.3:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
By default, Kubernetes will expose seven environment variables for each service. In most cases, the first two will be used for using kube-dns addon to do service discovery for us
- ${SVCNAME}_SERVICE_HOST
- ${SVCNAME}_SERVICE_PORT
- ${SVCNAME}_PORT
- ${SVCNAME}PORT${PORT}_${PROTOCAL}
- ${SVCNAME}PORT${PORT}_${PROTOCAL}_PROTO
- ${SVCNAME}PORT${PORT}_${PROTOCAL}_PORT
- ${SVCNAME}PORT${PORT}_${PROTOCAL}_ADDR
We'll create a pod called clusterip-chk to access nginx containers via nginx-service
export NGINX_SERVICE_SERVICE_HOST=10.42.1.3
cat << EOF > 3-2-3_clusterip_chk.yaml
apiVersion: v1
kind: Pod
metadata:
name: clusterip-chk
spec:
containers:
- name: centos
image: centos
command: ["/bin/sh", "-c", "while : ;do curl http://${NGINX_SERVICE_SERVICE_HOST}:80/; sleep 10; done"]
EOF
kubectl create -f 3-2-3_clusterip_chk.yaml
pod "clusterip-chk" created
Check stdout, see if we can access nginx pod successfully
kubectl logs -f clusterip-chk
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
100 612 100 612 0 0 269k 0 --:--:-- --:--:-- --:--:-- 597k
NodePort
If the service is set as NodePort, Kubernetes will allocate a port within a certain range on each node. Any traffic going to nodes on that port will be routed to the service port. Port number could be user-specified. If not specified, Kubernetes will randomly choose a port from range 30000 to 32767 without collision. On the other hand, if specified, the user should be responsible to manage the collision by themselves. NodePort includes the feature of ClusterIP. Kubernetes assigns an internal IP to the service.
cat << EOF > 3-2-3_nodeport.yaml
kind: Service
apiVersion: v1
metadata:
name: nginx-nodeport
spec:
type: NodePort
selector:
project: chapter3
service: web
ports:
- protocol: TCP
port: 80
targetPort: 80
EOF
kubectl create -f 3-2-3_nodeport.yaml
service "nginx-nodeport" created
kubectl get endpoints
NAME ENDPOINTS AGE
kubernetes 159.65.144.250:6443,159.65.156.182:6443,159.65.159.71:6443 + 2 more... 1h
nginx-nodeport 10.42.1.3:80,10.42.2.4:80,10.42.3.3:80 + 1 more... 1m
curl 10.42.1.3:80
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
kubectl expose services/nginx-nodeport --type="NodePort" --port 8080
LoadBalancer
This type is only usable with cloud provider support, such as Google Cloud Platform and Amazon Web Service. By creating LoadBalancer service, Kubernetes will provision a load balancer by the Cloud provider to the service.
ExternalName
Sometimes we leverage different services in the cloud. Kubernetes is flexible enough to be hybrid. ExternalName is one of the bridges to create a CNAME for external endpoints into the cluster.
Service without selectors
Service uses selectors to match the pods to direct the traffic. However, sometimes you need to implement a proxy to be the bridge between Kubernetes cluster and another namespace, another cluster, or external resources.
Create a service without selectors
cat << EOF > 3-2-3_service_wo_selector_srv.yaml
kind: Service
apiVersion: v1
metadata:
name: google-proxy
spec:
ports:
- protocol: TCP
port: 80
targetPort: 80
EOF
kubectl create -f 3-2-3_service_wo_selector_srv.yaml
service "google-proxy" created
No Kubernetes endpoint will be created since there is no selector. Kubernetes doesn't know where to route the traffic since no selector could match the pods. We'll have to create that on our own.
In the Endpoints object, the source addresses can't be DNS name, so we'll use nslookup to find the current Google IP from the domain, and add them into Endpoints.subsets.addresses.ip
nslookup www.google.com
Server: 67.207.67.3
Address: 67.207.67.3#53
Non-authoritative answer:
Name: www.google.com
Address: 172.217.166.132
# create endpoints for the ip from google.com
cat << EOF > 3-2-3_service_wo_selector_endpoints.yaml
kind: Endpoints
apiVersion: v1
metadata:
name: google-proxy
subsets:
- addresses:
- ip: 172.217.166.132
ports:
- port: 80
EOF
kubectl create -f 3-2-3_service_wo_selector_endpoints.yaml
endpoints "google-proxy" created
Let's create another pod in the cluster to access our Google proxy
export GOOGLE_PROXY_SERVICE_HOST=172.217.166.132
cat << EOF > 3-2-3_proxy-chk.yaml
apiVersion: v1
kind: Pod
metadata:
name: proxy-chk
spec:
containers:
- name: centos
image: centos
command: ["/bin/sh", "-c", "while : ;do curl -L http://${GOOGLE_PROXY_SERVICE_HOST}:80/; sleep 10; done"]
EOF
kubectl create -f 3-2-3_proxy-chk.yaml
pod "proxy-chk" created
Let's check the stdout from the pod
kubectl logs proxy-chk
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 219 100 219 0 0 1937 0 --:--:-- --:--:-- --:--:-- 1955
<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="en-IN"><head><meta content="text/html; charset=UTF-8" http-equiv="Content-Type"><meta content="/logos/doodles/2018
/world-cup-2018-day-1-5741876039647232-l.png" itemprop="image"><meta content="World Cup 2018 - Day 1" property="twitter:title"><meta content="Let the matches begin! Celebrate ⚽ around t
he 🌎🌍🌏 in today's #GoogleDoodle!" property="twitter:description"><meta content="Let the matches begin! Celebrate ⚽ around the 🌎🌍🌏 in toda
y's #GoogleDoodle!" property="og:description"><meta content="summary_large_image" property="twitter:card"><meta content="@GoogleDoodles" property="twitter:site"><meta content="https://www.goo
gle.com/logos/doodles/2018/world-cup-2018-day-1-5741876039647232-2x.png" property="twitter:image"><meta content="https://www.google.com/logos/doodles/2018/world-cup-2018-day-1-574187603964723
2-2x.png" property="og:image"><meta content="1150" property="og:image:width"><meta content="460" property="og:image:height"><title>Google</title><script nonce="hm4yHsDVv023E+mSwE8/2Q==">(func
tion(){window.google={kEI:'SwgiW7OQFYv4vgSO35_oDA',kEXPI:'0,201836,1151911,57,1957,930,88,39,241,160,336,214,852,48,30,75,566,60,9,89,43,154,321,62,190,2339794,240,187,32,21,329273,1294,12383
,2347,2508,32692,15247,864,772,7,792,7,5117,5471,6381,3335,2,2,2138,2471,2192,367,550,664,2102,113,2201,3191,224,502,5,1711,58,71,131,4628,479,575,1119,2,579,663,64,311,3,298,1820,58,2,2,2,54
2,755,284,1059,369,27,1349,505,730,377,26,1214,479,609,55,630,9,299,237,1032,280,494,194,1038,1021,278,2,694,148,282,1666,35,428,330,28,850,393,132,22,180,419,5,2,2,151,506,443,218,2,78,345,1
67,389,125,2,65,3,613,161,161,5,391,29,272,31,361,505,1151,685,260,214,82,236,60,6,145,195,79,623,205,163,500,11,40,35,57,80,28,334,123,7,483,373,383,105,394,902,182,7,3,25,506,19,381,4,4,108
,83,714,187,4,4,4,4,79,267,2330676,3685998,2545,9,5997613,2800173,4,1572,549,332,445,1,2,1,1,77,1,1,900,207,1,1,1,1,1,366,9,309,1,8,1,2,1,1,924,181,1,19,2,4,18,17,2,17,232,21,11,11,1,1,223104
74',authuser:0,kscs:'c9c918f0_SwgiW7OQFYv4vgSO35_oDA',kGL:'IN'};google.kHL='en-IN';})();google.time=function(){return(new Date).getTime()};(function(){google.lc=[];google.li=0;google.getEI=fu
nction(a){for(var b;a&&(!a.getAttribute||!(b=a.getAttribute("eid")));)a=a.parentNode;return b||google.kEI};google.getLEI=function(a){for(var b=null;a&&(!a.getAttribute||!(b=a.getAttribute("le
id")));)a=a.parentNode;return b};google.https=function(){return"https:"==window.location.protocol};google.ml=function(){return null};google.wl=function(a,b){try{google.ml(Error(a),!1,b)}catch
(d){}};google.log=function(a,b,d,c,g){if(a=google.logUrl(a,b,d,c,g)){b=new Image;var e=google.lc,f=google.li;e[f]=b;b.onerror=b.onload=b.onabort=function(){delete e[f]};google.vel&&google.vel
.lu&&google.vel.lu(a);b.src=a;google.li=f+1}};google.logUrl=function(a,b,d,c,g){var e="",f=google.ls||"";d||-1!=b.search("&ei=")||(e="&ei="+google.getEI(c),-1==b.search("&lei=")&&(c=google.ge
tLEI(c))&&(e+="&lei="+c));c="";!d&&google.cshid&&-1==b.search("&cshid=")&&(c="&cshid="+google.cshid);a=d||"/"+(g||"gen_204")+"?atyp=i&ct="+a+"&cad="+b+e+f+"&zx="+google.time()+c;/^http:/i.tes
t(a)&&google.https()&&(google.ml(Error("a"),!1,{src:a,glmm:1}),a="");return a};}).call(this);(function(){google.y={};google.x=function(a,b){if(a)var c=a.id;else{do c=Math.random();while(googl
e.y[c])}google.y[c]=[a,b];return!1};google.lm=[];google.plm=function(a){google.lm.push.apply(google.lm,a)};google.lq=[];google.load=function(a,b,c){google.lq.push([[a],b,c])};google.loadAll=f
unction(a,b){google.lq.push([a,b])};}).call(this);google.f={};var a=window.location,b=a.href.indexOf("#");if(0<=b){var c=a.href.substring(b+1);/(^|&)q=/.test(c)&&-1==c.indexOf("#")&&a.replace
("/search?"+c.replace(/(^|&)fp=[^&]*/g,"")+"&cad=h")};</script><style>#gbar,#guser{font-size:13px;padding-top:1px !important;}#gbar{height:22px}#guser{padding-bottom:7px !important;text-align
:right}.gbh,.gbd{border-top:1px solid #c9d7f1;font-size:1px}.gbh{height:0;position:absolute;top:24px;width:100%}@media all{.gb1{height:22px;margin-right:.5em;vertical-align:top}#gbar{float:le
ft}}a.gb1,a.gb4{text-decoration:underline !important}a.gb1,a.gb4{color:#00c !important}.gbi .gb4{color:#dd8e27 !important}.gbf .gb4{color:#900 !important}
</style><style>body,td,a,p,.h{font-family:arial,sans-serif}body{margin:0;overflow-y:scroll}#gog{padding:3px 8px 0}td{line-height:.8em}.gac_m td{line-height:17px}form{margin-bottom:20px}.h{col
or:#36c}.q{color:#00c}.ts td{padding:0}.ts{border-collapse:collapse}em{font-weight:bold;font-style:normal}.lst{height:25px;width:496px}.gsfi,.lst{font:18px arial,sans-serif}.gsfs{font:17px ar
ial,sans-serif}.ds{display:inline-box;display:inline-block;margin:3px 0 4px;margin-left:4px}input{font-family:inherit}a.gb1,a.gb2,a.gb3,a.gb4{color:#11c !important}body{background:#fff;color:
black}a{color:#11c;text-decoration:none}a:hover,a:active{text-decoration:underline}.fl a{color:#36c}a:visited{color:#551a8b}a.gb1,a.gb4{text-decoration:underline}a.gb3:hover{text-decoration:n
one}#ghead a.gb2:hover{color:#fff !important}.sblc{padding-top:5px}.sblc a{display:block;margin:2px 0;margin-left:13px;font-size:11px}.lsbb{background:#eee;border:solid 1px;border-color:#ccc
#999 #999 #ccc;height:30px}.lsbb{display:block}.ftl,#fll a{display:inline-block;margin:0 12px}.lsb{background:url(/images/nav_logo229.png) 0 -261px repeat-x;border:none;color:#000;cursor:poin
ter;height:30px;margin:0;outline:0;font:15px arial,sans-serif;vertical-align:top}.lsb:active{background:#ccc}.lst:focus{outline:none}</style><script nonce="hm4yHsDVv023E+mSwE8/2Q=="></script>
<link href="/images/branding/product/ico/googleg_lodp.ico" rel="shortcut icon"></head><body bgcolor="#fff"><script nonce="hm4yHsDVv023E+mSwE8/2Q==">(function(){var src='/images/nav_logo229.pn
g';var iesg=false;document.body.onload = function(){window.n && window.n();if (document.images){new Image().src=src;}
if (!iesg){document.f&&document.f.q.focus();document.gbqf&&document.gbqf.q.focus();}
}
0 0 0 14069 0 0 44889 0 --:--:-- --:--:-- --:--:-- 44889
We can now confirm the proxy works. The traffic to the service will be routed to the endpoints we specified.