2017-08-29 00:19:25 +03:00
# Bootstrapping the Kubernetes Control Plane
2020-06-20 16:21:26 +03:00
In this lab you will bootstrap the Kubernetes control plane across three VM instances and configure it for high availability. You will also create a load balancer that exposes the Kubernetes API Servers to remote clients. The following components will be installed on each node: Kubernetes API Server, Scheduler, and Controller Manager.
2017-08-29 00:19:25 +03:00
## Prerequisites
2020-06-20 16:21:26 +03:00
The commands in this lab must be run on each controller instance: `controller-0` , `controller-1` , and `controller-2` . Login to each controller instance using the `ssh` command. Example:
2017-08-29 00:19:25 +03:00
2020-06-20 10:24:03 +03:00
```bash
2020-06-20 16:21:26 +03:00
ssh controller-0
2017-08-29 00:19:25 +03:00
```
2018-05-12 19:54:18 +03:00
### Running commands in parallel with tmux
[tmux ](https://github.com/tmux/tmux/wiki ) can be used to run commands on multiple compute instances at the same time. See the [Running commands in parallel with tmux ](01-prerequisites.md#running-commands-in-parallel-with-tmux ) section in the Prerequisites lab.
2017-08-29 00:19:25 +03:00
## Provision the Kubernetes Control Plane
2018-05-12 19:54:18 +03:00
Create the Kubernetes configuration directory:
2020-06-20 10:24:03 +03:00
```bash
2018-05-12 19:54:18 +03:00
sudo mkdir -p /etc/kubernetes/config
```
2017-08-29 00:19:25 +03:00
### Download and Install the Kubernetes Controller Binaries
Download the official Kubernetes release binaries:
2020-06-20 10:24:03 +03:00
```bash
2017-08-29 00:19:25 +03:00
wget -q --show-progress --https-only --timestamping \
2019-09-14 21:41:56 +03:00
"https://storage.googleapis.com/kubernetes-release/release/v1.15.3/bin/linux/amd64/kube-apiserver" \
"https://storage.googleapis.com/kubernetes-release/release/v1.15.3/bin/linux/amd64/kube-controller-manager" \
"https://storage.googleapis.com/kubernetes-release/release/v1.15.3/bin/linux/amd64/kube-scheduler" \
"https://storage.googleapis.com/kubernetes-release/release/v1.15.3/bin/linux/amd64/kubectl"
2017-08-29 00:19:25 +03:00
```
Install the Kubernetes binaries:
2020-06-20 10:24:03 +03:00
```bash
2020-06-20 16:21:26 +03:00
chmod +x kube-apiserver kube-controller-manager kube-scheduler kubectl
sudo mv kube-apiserver kube-controller-manager kube-scheduler kubectl /usr/local/bin/
2017-08-29 00:19:25 +03:00
```
### Configure the Kubernetes API Server
2020-06-20 10:24:03 +03:00
```bash
2020-06-20 16:21:26 +03:00
sudo mkdir -p /var/lib/kubernetes/
2017-08-29 00:19:25 +03:00
2020-06-20 16:21:26 +03:00
sudo mv ca.pem ca-key.pem kubernetes-key.pem kubernetes.pem \
service-account-key.pem service-account.pem \
encryption-config.yaml /var/lib/kubernetes/
2017-08-29 00:19:25 +03:00
```
2020-06-20 16:21:26 +03:00
The instance internal IP address will be used to advertise the API Server to members of the cluster. Define the INTERNAL_IP (replace MY_NODE_INTERNAL_IP by the value):
2017-08-29 00:19:25 +03:00
2020-06-20 10:24:03 +03:00
```bash
2020-06-20 16:21:26 +03:00
INTERNAL_IP=MY_NODE_INTERNAL_IP
2017-08-29 00:19:25 +03:00
```
2020-06-20 16:21:26 +03:00
> Example for controller-0 : 192.168.8.10
2017-08-29 00:19:25 +03:00
Create the `kube-apiserver.service` systemd unit file:
2020-06-20 10:24:03 +03:00
```bash
2018-05-12 19:54:18 +03:00
cat < < EOF | sudo tee / etc / systemd / system / kube-apiserver . service
2017-08-29 00:19:25 +03:00
[Unit]
Description=Kubernetes API Server
2017-12-18 18:07:54 +03:00
Documentation=https://github.com/kubernetes/kubernetes
2017-08-29 00:19:25 +03:00
[Service]
ExecStart=/usr/local/bin/kube-apiserver \\
--advertise-address=${INTERNAL_IP} \\
--allow-privileged=true \\
--apiserver-count=3 \\
--audit-log-maxage=30 \\
--audit-log-maxbackup=3 \\
--audit-log-maxsize=100 \\
--audit-log-path=/var/log/audit.log \\
--authorization-mode=Node,RBAC \\
--bind-address=0.0.0.0 \\
--client-ca-file=/var/lib/kubernetes/ca.pem \\
2019-09-14 21:41:56 +03:00
--enable-admission-plugins=NamespaceLifecycle,NodeRestriction,LimitRanger,ServiceAccount,DefaultStorageClass,ResourceQuota \\
2017-08-29 00:19:25 +03:00
--etcd-cafile=/var/lib/kubernetes/ca.pem \\
--etcd-certfile=/var/lib/kubernetes/kubernetes.pem \\
--etcd-keyfile=/var/lib/kubernetes/kubernetes-key.pem \\
2020-06-20 16:21:26 +03:00
--etcd-servers=https://192.168.8.10:2379,https://192.168.8.11:2379,https://192.168.8.12:2379 \\
2017-08-29 00:19:25 +03:00
--event-ttl=1h \\
2019-09-14 21:41:56 +03:00
--encryption-provider-config=/var/lib/kubernetes/encryption-config.yaml \\
2017-08-29 00:19:25 +03:00
--kubelet-certificate-authority=/var/lib/kubernetes/ca.pem \\
--kubelet-client-certificate=/var/lib/kubernetes/kubernetes.pem \\
--kubelet-client-key=/var/lib/kubernetes/kubernetes-key.pem \\
--kubelet-https=true \\
2017-10-02 06:37:09 +03:00
--runtime-config=api/all \\
2018-05-12 19:54:18 +03:00
--service-account-key-file=/var/lib/kubernetes/service-account.pem \\
2017-08-29 00:19:25 +03:00
--service-cluster-ip-range=10.32.0.0/24 \\
--service-node-port-range=30000-32767 \\
--tls-cert-file=/var/lib/kubernetes/kubernetes.pem \\
--tls-private-key-file=/var/lib/kubernetes/kubernetes-key.pem \\
--v=2
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
```
### Configure the Kubernetes Controller Manager
2018-05-12 19:54:18 +03:00
Move the `kube-controller-manager` kubeconfig into place:
2020-06-20 10:24:03 +03:00
```bash
2018-05-12 19:54:18 +03:00
sudo mv kube-controller-manager.kubeconfig /var/lib/kubernetes/
```
2017-08-29 00:19:25 +03:00
Create the `kube-controller-manager.service` systemd unit file:
2020-06-20 10:24:03 +03:00
```bash
2018-05-12 19:54:18 +03:00
cat < < EOF | sudo tee / etc / systemd / system / kube-controller-manager . service
2017-08-29 00:19:25 +03:00
[Unit]
Description=Kubernetes Controller Manager
2017-12-18 18:07:54 +03:00
Documentation=https://github.com/kubernetes/kubernetes
2017-08-29 00:19:25 +03:00
[Service]
ExecStart=/usr/local/bin/kube-controller-manager \\
--address=0.0.0.0 \\
--cluster-cidr=10.200.0.0/16 \\
--cluster-name=kubernetes \\
--cluster-signing-cert-file=/var/lib/kubernetes/ca.pem \\
--cluster-signing-key-file=/var/lib/kubernetes/ca-key.pem \\
2018-05-12 19:54:18 +03:00
--kubeconfig=/var/lib/kubernetes/kube-controller-manager.kubeconfig \\
2017-08-29 00:19:25 +03:00
--leader-elect=true \\
--root-ca-file=/var/lib/kubernetes/ca.pem \\
2018-05-12 19:54:18 +03:00
--service-account-private-key-file=/var/lib/kubernetes/service-account-key.pem \\
2017-09-15 17:48:41 +03:00
--service-cluster-ip-range=10.32.0.0/24 \\
2018-05-12 19:54:18 +03:00
--use-service-account-credentials=true \\
2017-08-29 00:19:25 +03:00
--v=2
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
```
### Configure the Kubernetes Scheduler
2018-05-12 19:54:18 +03:00
Move the `kube-scheduler` kubeconfig into place:
2020-06-20 10:24:03 +03:00
```bash
2018-05-12 19:54:18 +03:00
sudo mv kube-scheduler.kubeconfig /var/lib/kubernetes/
```
Create the `kube-scheduler.yaml` configuration file:
2020-06-20 10:24:03 +03:00
```bash
2018-05-12 19:54:18 +03:00
cat < < EOF | sudo tee / etc / kubernetes / config / kube-scheduler . yaml
2019-09-14 21:41:56 +03:00
apiVersion: kubescheduler.config.k8s.io/v1alpha1
2018-05-12 19:54:18 +03:00
kind: KubeSchedulerConfiguration
clientConnection:
kubeconfig: "/var/lib/kubernetes/kube-scheduler.kubeconfig"
leaderElection:
leaderElect: true
EOF
```
2017-08-29 00:19:25 +03:00
Create the `kube-scheduler.service` systemd unit file:
2020-06-20 10:24:03 +03:00
```bash
2018-05-12 19:54:18 +03:00
cat < < EOF | sudo tee / etc / systemd / system / kube-scheduler . service
2017-08-29 00:19:25 +03:00
[Unit]
Description=Kubernetes Scheduler
2017-12-18 18:07:54 +03:00
Documentation=https://github.com/kubernetes/kubernetes
2017-08-29 00:19:25 +03:00
[Service]
ExecStart=/usr/local/bin/kube-scheduler \\
2018-05-12 19:54:18 +03:00
--config=/etc/kubernetes/config/kube-scheduler.yaml \\
2017-08-29 00:19:25 +03:00
--v=2
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
```
### Start the Controller Services
2020-06-20 10:24:03 +03:00
```bash
2020-06-20 16:21:26 +03:00
sudo systemctl daemon-reload
sudo systemctl enable kube-apiserver kube-controller-manager kube-scheduler
sudo systemctl start kube-apiserver kube-controller-manager kube-scheduler
2017-08-29 00:19:25 +03:00
```
2018-05-12 19:54:18 +03:00
> Allow up to 10 seconds for the Kubernetes API Server to fully initialize.
2017-08-29 00:19:25 +03:00
### Verification
2020-06-20 10:24:03 +03:00
```bash
2018-05-12 19:54:18 +03:00
kubectl get componentstatuses --kubeconfig admin.kubeconfig
2017-08-29 00:19:25 +03:00
```
2020-06-20 10:24:03 +03:00
```bash
2017-08-29 00:19:25 +03:00
NAME STATUS MESSAGE ERROR
2017-09-04 00:18:03 +03:00
controller-manager Healthy ok
scheduler Healthy ok
etcd-2 Healthy {"health": "true"}
etcd-0 Healthy {"health": "true"}
2017-08-29 00:19:25 +03:00
etcd-1 Healthy {"health": "true"}
```
2018-05-12 19:54:18 +03:00
Test the nginx HTTP health check proxy:
2020-06-20 10:24:03 +03:00
```bash
2018-05-12 19:54:18 +03:00
curl -H "Host: kubernetes.default.svc.cluster.local" -i http://127.0.0.1/healthz
```
2020-06-20 10:24:03 +03:00
```bash
2018-05-12 19:54:18 +03:00
HTTP/1.1 200 OK
Server: nginx/1.14.0 (Ubuntu)
2019-09-14 21:41:56 +03:00
Date: Sat, 14 Sep 2019 18:34:11 GMT
2018-05-12 19:54:18 +03:00
Content-Type: text/plain; charset=utf-8
Content-Length: 2
Connection: keep-alive
2019-09-14 21:41:56 +03:00
X-Content-Type-Options: nosniff
2018-05-12 19:54:18 +03:00
ok
```
2017-08-29 00:19:25 +03:00
> Remember to run the above commands on each controller node: `controller-0`, `controller-1`, and `controller-2`.
2017-10-02 06:37:09 +03:00
## RBAC for Kubelet Authorization
In this section you will configure RBAC permissions to allow the Kubernetes API Server to access the Kubelet API on each worker node. Access to the Kubelet API is required for retrieving metrics, logs, and executing commands in pods.
> This tutorial sets the Kubelet `--authorization-mode` flag to `Webhook`. Webhook mode uses the [SubjectAccessReview](https://kubernetes.io/docs/admin/authorization/#checking-api-access) API to determine authorization.
2019-09-14 21:41:56 +03:00
The commands in this section will effect the entire cluster and only need to be run once from one of the controller nodes.
2020-06-20 10:24:03 +03:00
```bash
2020-06-20 16:21:26 +03:00
ssh controller-0
2017-10-02 06:37:09 +03:00
```
Create the `system:kube-apiserver-to-kubelet` [ClusterRole ](https://kubernetes.io/docs/admin/authorization/rbac/#role-and-clusterrole ) with permissions to access the Kubelet API and perform most common tasks associated with managing pods:
2020-06-20 10:24:03 +03:00
```bash
2018-05-12 19:54:18 +03:00
cat < < EOF | kubectl apply --kubeconfig admin . kubeconfig -f -
2017-10-02 06:37:09 +03:00
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRole
metadata:
annotations:
rbac.authorization.kubernetes.io/autoupdate: "true"
labels:
kubernetes.io/bootstrapping: rbac-defaults
name: system:kube-apiserver-to-kubelet
rules:
- apiGroups:
- ""
resources:
- nodes/proxy
- nodes/stats
- nodes/log
- nodes/spec
- nodes/metrics
verbs:
- "*"
EOF
```
The Kubernetes API Server authenticates to the Kubelet as the `kubernetes` user using the client certificate as defined by the `--kubelet-client-certificate` flag.
Bind the `system:kube-apiserver-to-kubelet` ClusterRole to the `kubernetes` user:
2020-06-20 10:24:03 +03:00
```bash
2018-05-12 19:54:18 +03:00
cat < < EOF | kubectl apply --kubeconfig admin . kubeconfig -f -
2017-10-02 06:37:09 +03:00
apiVersion: rbac.authorization.k8s.io/v1beta1
kind: ClusterRoleBinding
metadata:
name: system:kube-apiserver
namespace: ""
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: system:kube-apiserver-to-kubelet
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: kubernetes
EOF
```
2017-08-29 00:19:25 +03:00
## The Kubernetes Frontend Load Balancer
2020-06-20 16:21:26 +03:00
In this section you will provision an Nginx load balancer to front the Kubernetes API Servers. The load balancer will listen on the public IP address (on the `gateway-01` VM).
2017-08-29 00:19:25 +03:00
2020-06-20 16:21:26 +03:00
### Provision an Nginx Load Balancer
2017-08-29 00:19:25 +03:00
2020-06-20 16:21:26 +03:00
Install the Nginx Load Balancer:
2017-08-29 00:19:25 +03:00
2020-06-20 16:21:26 +03:00
```bash
sudo apt-get update
sudo apt-get install -y nginx
```
Create the Nginx load balancer network configuration:
2017-08-29 00:19:25 +03:00
2020-06-20 10:24:03 +03:00
```bash
2020-06-20 16:21:26 +03:00
cat < < EOF > > /etc/nginx/nginx.conf
stream {
upstream controller_backend {
server 192.168.8.10:6443;
server 192.168.8.11:6443;
server 192.168.8.12:6443;
}
server {
listen 6443;
proxy_pass controller_backend;
health_check;
}
2018-05-12 19:54:18 +03:00
}
2020-06-20 16:21:26 +03:00
EOF
```
Restart the service:
```bash
sudo systemctl restart nginx
2017-08-29 00:19:25 +03:00
```
2020-06-20 16:21:26 +03:00
Enable the service:
```bash
sudo systemctl enable nginx
```
2017-08-29 00:19:25 +03:00
2020-06-20 16:21:26 +03:00
### Load Balancer Verification
2019-09-14 21:41:56 +03:00
2020-06-20 16:21:26 +03:00
Define the static public IP address (replace MY_PUBLIC_IP_ADDRESS with your public IP address on the `gateway-01` VM):
2017-08-29 00:19:25 +03:00
2020-06-20 10:24:03 +03:00
```bash
2020-06-20 16:21:26 +03:00
KUBERNETES_PUBLIC_ADDRESS=MY_PUBLIC_IP_ADDRESS
2017-08-29 00:19:25 +03:00
```
Make a HTTP request for the Kubernetes version info:
2020-06-20 10:24:03 +03:00
```bash
2017-10-02 06:37:09 +03:00
curl --cacert ca.pem https://${KUBERNETES_PUBLIC_ADDRESS}:6443/version
2017-08-29 00:19:25 +03:00
```
> output
2020-06-20 10:24:03 +03:00
```bash
2017-08-29 00:19:25 +03:00
{
"major": "1",
2019-09-14 21:41:56 +03:00
"minor": "15",
"gitVersion": "v1.15.3",
"gitCommit": "2d3c76f9091b6bec110a5e63777c332469e0cba2",
2017-08-29 00:19:25 +03:00
"gitTreeState": "clean",
2019-09-14 21:41:56 +03:00
"buildDate": "2019-08-19T11:05:50Z",
"goVersion": "go1.12.9",
2017-08-29 00:19:25 +03:00
"compiler": "gc",
"platform": "linux/amd64"
}
```
Next: [Bootstrapping the Kubernetes Worker Nodes ](09-bootstrapping-kubernetes-workers.md )