|
|
@@ -18,41 +18,24 @@ This guide uses a simple nginx server to demonstrate proof of concept. The same
|
|
|
|
|
|
|
|
|
|
|
|
We did this in a previous example, but lets do it once again and focus on the networking perspective. Create an nginx pod, and note that it has a container port specification:
|
|
|
|
We did this in a previous example, but lets do it once again and focus on the networking perspective. Create an nginx pod, and note that it has a container port specification:
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
{% include code.html language="yaml" file="run-my-nginx.yaml" ghlink="/docs/user-guide/run-my-nginx.yaml" %}
|
|
|
|
$ cat nginxrc.yaml
|
|
|
|
|
|
|
|
apiVersion: v1
|
|
|
|
|
|
|
|
kind: ReplicationController
|
|
|
|
|
|
|
|
metadata:
|
|
|
|
|
|
|
|
name: my-nginx
|
|
|
|
|
|
|
|
spec:
|
|
|
|
|
|
|
|
replicas: 2
|
|
|
|
|
|
|
|
template:
|
|
|
|
|
|
|
|
metadata:
|
|
|
|
|
|
|
|
labels:
|
|
|
|
|
|
|
|
app: nginx
|
|
|
|
|
|
|
|
spec:
|
|
|
|
|
|
|
|
containers:
|
|
|
|
|
|
|
|
- name: nginx
|
|
|
|
|
|
|
|
image: nginx
|
|
|
|
|
|
|
|
ports:
|
|
|
|
|
|
|
|
- containerPort: 80
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This makes it accessible from any node in your cluster. Check the nodes the pod is running on:
|
|
|
|
This makes it accessible from any node in your cluster. Check the nodes the pod is running on:
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
```shell
|
|
|
|
$ kubectl create -f ./nginxrc.yaml
|
|
|
|
$ kubectl create -f ./run-my-nginx.yaml
|
|
|
|
$ kubectl get pods -l app=nginx -o wide
|
|
|
|
$ kubectl get pods -l run=my-nginx -o wide
|
|
|
|
my-nginx-6isf4 1/1 Running 0 2h e2e-test-beeps-node-93ly
|
|
|
|
NAME READY STATUS RESTARTS AGE NODE
|
|
|
|
my-nginx-t26zt 1/1 Running 0 2h e2e-test-beeps-node-93ly
|
|
|
|
my-nginx-3800858182-jr4a2 1/1 Running 0 13s kubernetes-minion-905m
|
|
|
|
|
|
|
|
my-nginx-3800858182-kna2y 1/1 Running 0 13s kubernetes-minion-ljyd
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Check your pods' IPs:
|
|
|
|
Check your pods' IPs:
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
```shell
|
|
|
|
$ kubectl get pods -l app=nginx -o json | grep podIP
|
|
|
|
$ kubectl get pods -l run=my-nginx -o yaml | grep podIP
|
|
|
|
"podIP": "10.245.0.15",
|
|
|
|
podIP: 10.244.3.4
|
|
|
|
"podIP": "10.245.0.14",
|
|
|
|
podIP: 10.244.2.5
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
You should be able to ssh into any node in your cluster and curl both IPs. Note that the containers are *not* using port 80 on the node, nor are there any special NAT rules to route traffic to the pod. This means you can run multiple nginx pods on the same node all using the same containerPort and access them from any other pod or node in your cluster using IP. Like Docker, ports can still be published to the host node's interface(s), but the need for this is radically diminished because of the networking model.
|
|
|
|
You should be able to ssh into any node in your cluster and curl both IPs. Note that the containers are *not* using port 80 on the node, nor are there any special NAT rules to route traffic to the pod. This means you can run multiple nginx pods on the same node all using the same containerPort and access them from any other pod or node in your cluster using IP. Like Docker, ports can still be published to the host node's interface(s), but the need for this is radically diminished because of the networking model.
|
|
|
@@ -61,59 +44,51 @@ You can read more about [how we achieve this](/docs/admin/networking/#how-to-ach
|
|
|
|
|
|
|
|
|
|
|
|
## Creating a Service
|
|
|
|
## Creating a Service
|
|
|
|
|
|
|
|
|
|
|
|
So we have pods running nginx in a flat, cluster wide, address space. In theory, you could talk to these pods directly, but what happens when a node dies? The pods die with it, and the replication controller will create new ones, with different IPs. This is the problem a Service solves.
|
|
|
|
So we have pods running nginx in a flat, cluster wide, address space. In theory, you could talk to these pods directly, but what happens when a node dies? The pods die with it, and the Deployment will create new ones, with different IPs. This is the problem a Service solves.
|
|
|
|
|
|
|
|
|
|
|
|
A Kubernetes Service is an abstraction which defines a logical set of Pods running somewhere in your cluster, that all provide the same functionality. When created, each Service is assigned a unique IP address (also called clusterIP). This address is tied to the lifespan of the Service, and will not change while the Service is alive. Pods can be configured to talk to the Service, and know that communication to the Service will be automatically load-balanced out to some pod that is a member of the Service.
|
|
|
|
A Kubernetes Service is an abstraction which defines a logical set of Pods running somewhere in your cluster, that all provide the same functionality. When created, each Service is assigned a unique IP address (also called clusterIP). This address is tied to the lifespan of the Service, and will not change while the Service is alive. Pods can be configured to talk to the Service, and know that communication to the Service will be automatically load-balanced out to some pod that is a member of the Service.
|
|
|
|
|
|
|
|
|
|
|
|
You can create a Service for your 2 nginx replicas with the following yaml:
|
|
|
|
You can create a Service for your 2 nginx replicas with `kubectl expose`:
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
```shell
|
|
|
|
$ cat nginxsvc.yaml
|
|
|
|
$ kubectl expose deployment/my-nginx
|
|
|
|
apiVersion: v1
|
|
|
|
service "my-nginx" exposed
|
|
|
|
kind: Service
|
|
|
|
|
|
|
|
metadata:
|
|
|
|
|
|
|
|
name: nginxsvc
|
|
|
|
|
|
|
|
labels:
|
|
|
|
|
|
|
|
app: nginx
|
|
|
|
|
|
|
|
spec:
|
|
|
|
|
|
|
|
ports:
|
|
|
|
|
|
|
|
- port: 80
|
|
|
|
|
|
|
|
protocol: TCP
|
|
|
|
|
|
|
|
selector:
|
|
|
|
|
|
|
|
app: nginx
|
|
|
|
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
This is equivalent to `kubectl create -f` the following yaml:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{% include code.html language="yaml" file="nginx-svc.yaml" ghlink="/docs/user-guide/nginx-svc.yaml" %}
|
|
|
|
|
|
|
|
|
|
|
|
This specification will create a Service which targets TCP port 80 on any Pod with the `app=nginx` label, and expose it on an abstracted Service port (`targetPort`: is the port the container accepts traffic on, `port`: is the abstracted Service port, which can be any port other pods use to access the Service). View [service API object](/docs/api-reference/v1/definitions/#_v1_service) to see the list of supported fields in service definition.
|
|
|
|
This specification will create a Service which targets TCP port 80 on any Pod with the `app=nginx` label, and expose it on an abstracted Service port (`targetPort`: is the port the container accepts traffic on, `port`: is the abstracted Service port, which can be any port other pods use to access the Service). View [service API object](/docs/api-reference/v1/definitions/#_v1_service) to see the list of supported fields in service definition.
|
|
|
|
Check your Service:
|
|
|
|
Check your Service:
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
```shell
|
|
|
|
$ kubectl get svc
|
|
|
|
$ kubectl get svc my-nginx
|
|
|
|
NAME CLUSTER_IP EXTERNAL_IP PORT(S) SELECTOR AGE
|
|
|
|
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
|
|
|
kubernetes 10.179.240.1 <none> 443/TCP <none> 8d
|
|
|
|
my-nginx 10.0.162.149 <none> 80/TCP 21s
|
|
|
|
nginxsvc 10.179.252.126 122.222.183.144 80/TCP,81/TCP,82/TCP run=nginx2 11m
|
|
|
|
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
As mentioned previously, a Service is backed by a group of pods. These pods are exposed through `endpoints`. The Service's selector will be evaluated continuously and the results will be POSTed to an Endpoints object also named `nginxsvc`. When a pod dies, it is automatically removed from the endpoints, and new pods matching the Service's selector will automatically get added to the endpoints. Check the endpoints, and note that the IPs are the same as the pods created in the first step:
|
|
|
|
As mentioned previously, a Service is backed by a group of pods. These pods are exposed through `endpoints`. The Service's selector will be evaluated continuously and the results will be POSTed to an Endpoints object also named `my-nginx`. When a pod dies, it is automatically removed from the endpoints, and new pods matching the Service's selector will automatically get added to the endpoints. Check the endpoints, and note that the IPs are the same as the pods created in the first step:
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
```shell
|
|
|
|
$ kubectl describe svc nginxsvc
|
|
|
|
$ kubectl describe svc my-nginx
|
|
|
|
Name: nginxsvc
|
|
|
|
Name: my-nginx
|
|
|
|
Namespace: default
|
|
|
|
Namespace: default
|
|
|
|
Labels: app=nginx
|
|
|
|
Labels: run=my-nginx
|
|
|
|
Selector: app=nginx
|
|
|
|
Selector: run=my-nginx
|
|
|
|
Type: ClusterIP
|
|
|
|
Type: ClusterIP
|
|
|
|
IP: 10.0.116.146
|
|
|
|
IP: 10.0.162.149
|
|
|
|
Port: <unnamed> 80/TCP
|
|
|
|
Port: <unset> 80/TCP
|
|
|
|
Endpoints: 10.245.0.14:80,10.245.0.15:80
|
|
|
|
Endpoints: 10.244.2.5:80,10.244.3.4:80
|
|
|
|
Session Affinity: None
|
|
|
|
Session Affinity: None
|
|
|
|
No events.
|
|
|
|
No events.
|
|
|
|
|
|
|
|
|
|
|
|
$ kubectl get ep
|
|
|
|
$ kubectl get ep my-nginx
|
|
|
|
NAME ENDPOINTS
|
|
|
|
NAME ENDPOINTS AGE
|
|
|
|
nginxsvc 10.245.0.14:80,10.245.0.15:80
|
|
|
|
my-nginx 10.244.2.5:80,10.244.3.4:80 1m
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
You should now be able to curl the nginx Service on `10.0.116.146:80` from any node in your cluster. Note that the Service IP is completely virtual, it never hits the wire, if you're curious about how this works you can read more about the [service proxy](/docs/user-guide/services/#virtual-ips-and-service-proxies).
|
|
|
|
You should now be able to curl the nginx Service on `<CLUSTER-IP>:<PORT>` from any node in your cluster. Note that the Service IP is completely virtual, it never hits the wire, if you're curious about how this works you can read more about the [service proxy](/docs/user-guide/services/#virtual-ips-and-service-proxies).
|
|
|
|
|
|
|
|
|
|
|
|
## Accessing the Service
|
|
|
|
## Accessing the Service
|
|
|
|
|
|
|
|
|
|
|
@@ -121,28 +96,35 @@ Kubernetes supports 2 primary modes of finding a Service - environment variables
|
|
|
|
|
|
|
|
|
|
|
|
### Environment Variables
|
|
|
|
### Environment Variables
|
|
|
|
|
|
|
|
|
|
|
|
When a Pod is run on a Node, the kubelet adds a set of environment variables for each active Service. This introduces an ordering problem. To see why, inspect the environment of your running nginx pods:
|
|
|
|
When a Pod is run on a Node, the kubelet adds a set of environment variables for each active Service. This introduces an ordering problem. To see why, inspect the environment of your running nginx pods (your pod name will be different):
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
```shell
|
|
|
|
$ kubectl exec my-nginx-6isf4 -- printenv | grep SERVICE
|
|
|
|
$ kubectl exec my-nginx-3800858182-jr4a2 -- printenv | grep SERVICE
|
|
|
|
KUBERNETES_SERVICE_HOST=10.0.0.1
|
|
|
|
KUBERNETES_SERVICE_HOST=10.0.0.1
|
|
|
|
KUBERNETES_SERVICE_PORT=443
|
|
|
|
KUBERNETES_SERVICE_PORT=443
|
|
|
|
|
|
|
|
KUBERNETES_SERVICE_PORT_HTTPS=443
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Note there's no mention of your Service. This is because you created the replicas before the Service. Another disadvantage of doing this is that the scheduler might put both pods on the same machine, which will take your entire Service down if it dies. We can do this the right way by killing the 2 pods and waiting for the replication controller to recreate them. This time around the Service exists *before* the replicas. This will given you scheduler level Service spreading of your pods (provided all your nodes have equal capacity), as well as the right environment variables:
|
|
|
|
Note there's no mention of your Service. This is because you created the replicas before the Service. Another disadvantage of doing this is that the scheduler might put both pods on the same machine, which will take your entire Service down if it dies. We can do this the right way by killing the 2 pods and waiting for the Deployment to recreate them. This time around the Service exists *before* the replicas. This will given you scheduler level Service spreading of your pods (provided all your nodes have equal capacity), as well as the right environment variables:
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
```shell
|
|
|
|
$ kubectl scale rc my-nginx --replicas=0; kubectl scale rc my-nginx --replicas=2;
|
|
|
|
$ kubectl scale deployment my-nginx --replicas=0; kubectl scale deployment my-nginx --replicas=2;
|
|
|
|
$ kubectl get pods -l app=nginx -o wide
|
|
|
|
|
|
|
|
NAME READY STATUS RESTARTS AGE NODE
|
|
|
|
|
|
|
|
my-nginx-5j8ok 1/1 Running 0 2m node1
|
|
|
|
|
|
|
|
my-nginx-90vaf 1/1 Running 0 2m node2
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$ kubectl exec my-nginx-5j8ok -- printenv | grep SERVICE
|
|
|
|
$ kubectl get pods -l run=my-nginx -o wide
|
|
|
|
|
|
|
|
NAME READY STATUS RESTARTS AGE NODE
|
|
|
|
|
|
|
|
my-nginx-3800858182-e9ihh 1/1 Running 0 5s kubernetes-minion-ljyd
|
|
|
|
|
|
|
|
my-nginx-3800858182-j4rm4 1/1 Running 0 5s kubernetes-minion-905m
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
You may notice that the pods have different names, since they are killed and recreated.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
|
|
|
$ kubectl exec my-nginx-3800858182-e9ihh -- printenv | grep SERVICE
|
|
|
|
KUBERNETES_SERVICE_PORT=443
|
|
|
|
KUBERNETES_SERVICE_PORT=443
|
|
|
|
NGINXSVC_SERVICE_HOST=10.0.116.146
|
|
|
|
MY_NGINX_SERVICE_HOST=10.0.162.149
|
|
|
|
KUBERNETES_SERVICE_HOST=10.0.0.1
|
|
|
|
KUBERNETES_SERVICE_HOST=10.0.0.1
|
|
|
|
NGINXSVC_SERVICE_PORT=80
|
|
|
|
MY_NGINX_SERVICE_PORT=80
|
|
|
|
|
|
|
|
KUBERNETES_SERVICE_PORT_HTTPS=443
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### DNS
|
|
|
|
### DNS
|
|
|
@@ -151,43 +133,27 @@ Kubernetes offers a DNS cluster addon Service that uses skydns to automatically
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
```shell
|
|
|
|
$ kubectl get services kube-dns --namespace=kube-system
|
|
|
|
$ kubectl get services kube-dns --namespace=kube-system
|
|
|
|
NAME CLUSTER_IP EXTERNAL_IP PORT(S) SELECTOR AGE
|
|
|
|
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
|
|
|
kube-dns 10.179.240.10 <none> 53/UDP,53/TCP k8s-app=kube-dns 8d
|
|
|
|
kube-dns 10.0.0.10 <none> 53/UDP,53/TCP 8m
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
If it isn't running, you can [enable it](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/dns/README.md#how-do-i-configure-it). The rest of this section will assume you have a Service with a long lived IP (nginxsvc), and a dns server that has assigned a name to that IP (the kube-dns cluster addon), so you can talk to the Service from any pod in your cluster using standard methods (e.g. gethostbyname). Let's create another pod to test this:
|
|
|
|
If it isn't running, you can [enable it](http://releases.k8s.io/{{page.githubbranch}}/cluster/addons/dns/README.md#how-do-i-configure-it). The rest of this section will assume you have a Service with a long lived IP (my-nginx), and a dns server that has assigned a name to that IP (the kube-dns cluster addon), so you can talk to the Service from any pod in your cluster using standard methods (e.g. gethostbyname). Let's run another curl application to test this:
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
|
|
|
|
$ cat curlpod.yaml
|
|
|
|
|
|
|
|
apiVersion: v1
|
|
|
|
|
|
|
|
kind: Pod
|
|
|
|
|
|
|
|
metadata:
|
|
|
|
|
|
|
|
name: curlpod
|
|
|
|
|
|
|
|
spec:
|
|
|
|
|
|
|
|
containers:
|
|
|
|
|
|
|
|
- image: radial/busyboxplus:curl
|
|
|
|
|
|
|
|
command:
|
|
|
|
|
|
|
|
- sleep
|
|
|
|
|
|
|
|
- "3600"
|
|
|
|
|
|
|
|
imagePullPolicy: IfNotPresent
|
|
|
|
|
|
|
|
name: curlcontainer
|
|
|
|
|
|
|
|
restartPolicy: Always
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
And perform a lookup of the nginx Service
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
```shell
|
|
|
|
$ kubectl create -f ./curlpod.yaml
|
|
|
|
$ kubectl run curl --image=radial/busyboxplus:curl -i --tty
|
|
|
|
default/curlpod
|
|
|
|
Waiting for pod default/curl-131556218-9fnch to be running, status is Pending, pod ready: false
|
|
|
|
$ kubectl get pods curlpod
|
|
|
|
Hit enter for command prompt
|
|
|
|
NAME READY STATUS RESTARTS AGE
|
|
|
|
```
|
|
|
|
curlpod 1/1 Running 0 18s
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$ kubectl exec curlpod -- nslookup nginxsvc
|
|
|
|
Then, hit enter and run `nslookup my-nginx`:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
|
|
|
|
[ root@curl-131556218-9fnch:/ ]$ nslookup my-nginx
|
|
|
|
Server: 10.0.0.10
|
|
|
|
Server: 10.0.0.10
|
|
|
|
Address 1: 10.0.0.10
|
|
|
|
Address 1: 10.0.0.10
|
|
|
|
Name: nginxsvc
|
|
|
|
|
|
|
|
Address 1: 10.0.116.146
|
|
|
|
Name: my-nginx
|
|
|
|
|
|
|
|
Address 1: 10.0.162.149
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
## Securing the Service
|
|
|
|
## Securing the Service
|
|
|
@@ -212,73 +178,27 @@ nginxsecret Opaque 2
|
|
|
|
|
|
|
|
|
|
|
|
Now modify your nginx replicas to start a https server using the certificate in the secret, and the Service, to expose both ports (80 and 443):
|
|
|
|
Now modify your nginx replicas to start a https server using the certificate in the secret, and the Service, to expose both ports (80 and 443):
|
|
|
|
|
|
|
|
|
|
|
|
```yaml
|
|
|
|
{% include code.html language="yaml" file="nginx-secure-app.yaml" ghlink="/docs/user-guide/nginx-secure-app" %}
|
|
|
|
$ cat nginx-app.yaml
|
|
|
|
|
|
|
|
apiVersion: v1
|
|
|
|
|
|
|
|
kind: Service
|
|
|
|
|
|
|
|
metadata:
|
|
|
|
|
|
|
|
name: nginxsvc
|
|
|
|
|
|
|
|
labels:
|
|
|
|
|
|
|
|
app: nginx
|
|
|
|
|
|
|
|
spec:
|
|
|
|
|
|
|
|
type: NodePort
|
|
|
|
|
|
|
|
ports:
|
|
|
|
|
|
|
|
- port: 8080
|
|
|
|
|
|
|
|
targetPort: 80
|
|
|
|
|
|
|
|
protocol: TCP
|
|
|
|
|
|
|
|
name: http
|
|
|
|
|
|
|
|
- port: 443
|
|
|
|
|
|
|
|
protocol: TCP
|
|
|
|
|
|
|
|
name: https
|
|
|
|
|
|
|
|
selector:
|
|
|
|
|
|
|
|
app: nginx
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
apiVersion: v1
|
|
|
|
|
|
|
|
kind: ReplicationController
|
|
|
|
|
|
|
|
metadata:
|
|
|
|
|
|
|
|
name: my-nginx
|
|
|
|
|
|
|
|
spec:
|
|
|
|
|
|
|
|
replicas: 1
|
|
|
|
|
|
|
|
template:
|
|
|
|
|
|
|
|
metadata:
|
|
|
|
|
|
|
|
labels:
|
|
|
|
|
|
|
|
app: nginx
|
|
|
|
|
|
|
|
spec:
|
|
|
|
|
|
|
|
volumes:
|
|
|
|
|
|
|
|
- name: secret-volume
|
|
|
|
|
|
|
|
secret:
|
|
|
|
|
|
|
|
secretName: nginxsecret
|
|
|
|
|
|
|
|
containers:
|
|
|
|
|
|
|
|
- name: nginxhttps
|
|
|
|
|
|
|
|
image: bprashanth/nginxhttps:1.0
|
|
|
|
|
|
|
|
ports:
|
|
|
|
|
|
|
|
- containerPort: 443
|
|
|
|
|
|
|
|
- containerPort: 80
|
|
|
|
|
|
|
|
volumeMounts:
|
|
|
|
|
|
|
|
- mountPath: /etc/nginx/ssl
|
|
|
|
|
|
|
|
name: secret-volume
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Noteworthy points about the nginx-app manifest:
|
|
|
|
Noteworthy points about the nginx-secure-app manifest:
|
|
|
|
|
|
|
|
|
|
|
|
- It contains both rc and service specification in the same file
|
|
|
|
- It contains both rc and service specification in the same file
|
|
|
|
- The [nginx server](https://github.com/kubernetes/kubernetes/tree/{{page.githubbranch}}/examples/https-nginx/default.conf) serves http traffic on port 80 and https traffic on 443, and nginx Service exposes both ports.
|
|
|
|
- The [nginx server](https://github.com/kubernetes/kubernetes/tree/{{page.githubbranch}}/examples/https-nginx/default.conf) serves http traffic on port 80 and https traffic on 443, and nginx Service exposes both ports.
|
|
|
|
- Each container has access to the keys through a volume mounted at /etc/nginx/ssl. This is setup *before* the nginx server is started.
|
|
|
|
- Each container has access to the keys through a volume mounted at /etc/nginx/ssl. This is setup *before* the nginx server is started.
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
```shell
|
|
|
|
|
|
|
|
$ kubectl apply -f ./nginx-secure-app.yaml
|
|
|
|
$ kubectl delete rc,svc -l app=nginx; kubectl create -f ./nginx-app.yaml
|
|
|
|
$ kubectl delete rc,svc -l app=nginx; kubectl create -f ./nginx-app.yaml
|
|
|
|
replicationcontrollers/my-nginx
|
|
|
|
service "my-nginx" configured
|
|
|
|
services/nginxsvc
|
|
|
|
deployment "my-nginx" configured
|
|
|
|
services/nginxsvc
|
|
|
|
|
|
|
|
replicationcontrollers/my-nginx
|
|
|
|
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
At this point you can reach the nginx server from any node.
|
|
|
|
At this point you can reach the nginx server from any node.
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
```shell
|
|
|
|
$ kubectl get pods -o json | grep -i podip
|
|
|
|
$ kubectl get pods -o yaml | grep -i podip
|
|
|
|
"podIP": "10.1.0.80",
|
|
|
|
podIP: 10.244.3.5
|
|
|
|
node $ curl -k https://10.1.0.80
|
|
|
|
node $ curl -k https://10.244.3.5
|
|
|
|
...
|
|
|
|
...
|
|
|
|
<h1>Welcome to nginx!</h1>
|
|
|
|
<h1>Welcome to nginx!</h1>
|
|
|
|
```
|
|
|
|
```
|
|
|
@@ -287,41 +207,15 @@ Note how we supplied the `-k` parameter to curl in the last step, this is becaus
|
|
|
|
so we have to tell curl to ignore the CName mismatch. By creating a Service we linked the CName used in the certificate with the actual DNS name used by pods during Service lookup.
|
|
|
|
so we have to tell curl to ignore the CName mismatch. By creating a Service we linked the CName used in the certificate with the actual DNS name used by pods during Service lookup.
|
|
|
|
Lets test this from a pod (the same secret is being reused for simplicity, the pod only needs nginx.crt to access the Service):
|
|
|
|
Lets test this from a pod (the same secret is being reused for simplicity, the pod only needs nginx.crt to access the Service):
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
{% include code.html language="yaml" file="curlpod.yaml" ghlink="/docs/user-guide/curlpod.yaml" %}
|
|
|
|
$ cat curlpod.yaml
|
|
|
|
|
|
|
|
apiVersion: v1
|
|
|
|
|
|
|
|
kind: ReplicationController
|
|
|
|
|
|
|
|
metadata:
|
|
|
|
|
|
|
|
name: curlrc
|
|
|
|
|
|
|
|
spec:
|
|
|
|
|
|
|
|
replicas: 1
|
|
|
|
|
|
|
|
template:
|
|
|
|
|
|
|
|
metadata:
|
|
|
|
|
|
|
|
labels:
|
|
|
|
|
|
|
|
app: curlpod
|
|
|
|
|
|
|
|
spec:
|
|
|
|
|
|
|
|
volumes:
|
|
|
|
|
|
|
|
- name: secret-volume
|
|
|
|
|
|
|
|
secret:
|
|
|
|
|
|
|
|
secretName: nginxsecret
|
|
|
|
|
|
|
|
containers:
|
|
|
|
|
|
|
|
- name: curlpod
|
|
|
|
|
|
|
|
command:
|
|
|
|
|
|
|
|
- sh
|
|
|
|
|
|
|
|
- -c
|
|
|
|
|
|
|
|
- while true; do sleep 1; done
|
|
|
|
|
|
|
|
image: radial/busyboxplus:curl
|
|
|
|
|
|
|
|
volumeMounts:
|
|
|
|
|
|
|
|
- mountPath: /etc/nginx/ssl
|
|
|
|
|
|
|
|
name: secret-volume
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
$ kubectl create -f ./curlpod.yaml
|
|
|
|
$ kubectl create -f ./curlpod.yaml
|
|
|
|
$ kubectl get pods
|
|
|
|
$ kubectl get pods
|
|
|
|
NAME READY STATUS RESTARTS AGE
|
|
|
|
NAME READY STATUS RESTARTS AGE
|
|
|
|
curlpod 1/1 Running 0 2m
|
|
|
|
curlpod 1/1 Running 0 2m
|
|
|
|
my-nginx-7006w 1/1 Running 0 24m
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$ kubectl exec curlpod -- curl https://nginxsvc --cacert /etc/nginx/ssl/nginx.crt
|
|
|
|
$ kubectl exec curlpod -- curl https://my-nginx --cacert /etc/nginx/ssl/nginx.crt
|
|
|
|
...
|
|
|
|
...
|
|
|
|
<title>Welcome to nginx!</title>
|
|
|
|
<title>Welcome to nginx!</title>
|
|
|
|
...
|
|
|
|
...
|
|
|
@@ -332,62 +226,62 @@ $ kubectl exec curlpod -- curl https://nginxsvc --cacert /etc/nginx/ssl/nginx.cr
|
|
|
|
For some parts of your applications you may want to expose a Service onto an external IP address. Kubernetes supports two ways of doing this: NodePorts and LoadBalancers. The Service created in the last section already used `NodePort`, so your nginx https replica is ready to serve traffic on the internet if your node has a public IP.
|
|
|
|
For some parts of your applications you may want to expose a Service onto an external IP address. Kubernetes supports two ways of doing this: NodePorts and LoadBalancers. The Service created in the last section already used `NodePort`, so your nginx https replica is ready to serve traffic on the internet if your node has a public IP.
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
```shell
|
|
|
|
$ kubectl get svc nginxsvc -o json | grep -i nodeport -C 5
|
|
|
|
$ kubectl get svc my-nginx -o yaml | grep nodePort -C 5
|
|
|
|
{
|
|
|
|
uid: 07191fb3-f61a-11e5-8ae5-42010af00002
|
|
|
|
"name": "http",
|
|
|
|
spec:
|
|
|
|
"protocol": "TCP",
|
|
|
|
clusterIP: 10.0.162.149
|
|
|
|
"port": 80,
|
|
|
|
ports:
|
|
|
|
"targetPort": 80,
|
|
|
|
- name: http
|
|
|
|
"nodePort": 32188
|
|
|
|
nodePort: 31704
|
|
|
|
},
|
|
|
|
port: 8080
|
|
|
|
{
|
|
|
|
protocol: TCP
|
|
|
|
"name": "https",
|
|
|
|
targetPort: 80
|
|
|
|
"protocol": "TCP",
|
|
|
|
- name: https
|
|
|
|
"port": 443,
|
|
|
|
nodePort: 32453
|
|
|
|
"targetPort": 443,
|
|
|
|
port: 443
|
|
|
|
"nodePort": 30645
|
|
|
|
protocol: TCP
|
|
|
|
}
|
|
|
|
targetPort: 443
|
|
|
|
|
|
|
|
selector:
|
|
|
|
|
|
|
|
run: my-nginx
|
|
|
|
|
|
|
|
|
|
|
|
$ kubectl get nodes -o json | grep ExternalIP -C 2
|
|
|
|
$ kubectl get nodes -o yaml | grep ExternalIP -C 1
|
|
|
|
{
|
|
|
|
- address: 104.197.41.11
|
|
|
|
"type": "ExternalIP",
|
|
|
|
type: ExternalIP
|
|
|
|
"address": "104.197.63.17"
|
|
|
|
allocatable:
|
|
|
|
}
|
|
|
|
|
|
|
|
--
|
|
|
|
--
|
|
|
|
},
|
|
|
|
- address: 23.251.152.56
|
|
|
|
{
|
|
|
|
type: ExternalIP
|
|
|
|
"type": "ExternalIP",
|
|
|
|
allocatable:
|
|
|
|
"address": "104.154.89.170"
|
|
|
|
...
|
|
|
|
}
|
|
|
|
|
|
|
|
$ curl https://104.197.63.17:30645 -k
|
|
|
|
$ curl https://<EXTERNAL-IP>:<NODE-PORT> -k
|
|
|
|
...
|
|
|
|
...
|
|
|
|
<h1>Welcome to nginx!</h1>
|
|
|
|
<h1>Welcome to nginx!</h1>
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Lets now recreate the Service to use a cloud load balancer, just change the `Type` of Service in the nginx-app.yaml from `NodePort` to `LoadBalancer`:
|
|
|
|
Lets now recreate the Service to use a cloud load balancer, just change the `Type` of `my-nginx` Service from `NodePort` to `LoadBalancer`:
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
```shell
|
|
|
|
$ kubectl delete rc,svc -l app=nginx
|
|
|
|
$ kubectl edit svc my-nginx
|
|
|
|
$ kubectl create -f ./nginx-app.yaml
|
|
|
|
$ kubectl get svc my-nginx
|
|
|
|
$ kubectl get svc nginxsvc
|
|
|
|
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
|
|
|
|
NAME CLUSTER_IP EXTERNAL_IP PORT(S) SELECTOR AGE
|
|
|
|
my-nginx 10.0.162.149 162.222.184.144 80/TCP,81/TCP,82/TCP 21s
|
|
|
|
nginxsvc 10.179.252.126 162.222.184.144 80/TCP,81/TCP,82/TCP run=nginx2 13m
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
$ curl https://162.22.184.144 -k
|
|
|
|
$ curl https://<EXTERNAL-IP> -k
|
|
|
|
...
|
|
|
|
...
|
|
|
|
<title>Welcome to nginx!</title>
|
|
|
|
<title>Welcome to nginx!</title>
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
The IP address in the `EXTERNAL_IP` column is the one that is available on the public internet. The `CLUSTER_IP` is only available inside your
|
|
|
|
The IP address in the `EXTERNAL-IP` column is the one that is available on the public internet. The `CLUSTER-IP` is only available inside your
|
|
|
|
cluster/private cloud network.
|
|
|
|
cluster/private cloud network.
|
|
|
|
|
|
|
|
|
|
|
|
Note that on AWS, type `LoadBalancer` creates an ELB, which uses a (long)
|
|
|
|
Note that on AWS, type `LoadBalancer` creates an ELB, which uses a (long)
|
|
|
|
hostname, not an IP. It's too long to fit in the standard `kubectl get svc`
|
|
|
|
hostname, not an IP. It's too long to fit in the standard `kubectl get svc`
|
|
|
|
output, in fact, so you'll need to do `kubectl describe service nginxsvc` to
|
|
|
|
output, in fact, so you'll need to do `kubectl describe service my-nginx` to
|
|
|
|
see it. You'll see something like this:
|
|
|
|
see it. You'll see something like this:
|
|
|
|
|
|
|
|
|
|
|
|
```shell
|
|
|
|
```shell
|
|
|
|
> kubectl describe service nginxsvc
|
|
|
|
$ kubectl describe service my-nginx
|
|
|
|
...
|
|
|
|
...
|
|
|
|
LoadBalancer Ingress: a320587ffd19711e5a37606cf4a74574-1142138393.us-east-1.elb.amazonaws.com
|
|
|
|
LoadBalancer Ingress: a320587ffd19711e5a37606cf4a74574-1142138393.us-east-1.elb.amazonaws.com
|
|
|
|
...
|
|
|
|
...
|
|
|
|