Task: Setup Kubernetes
Table of contents:
Set of nodes to install Kubernetes on. Virtual Machives will do.
We may want to name kubernetes hosts in order to tell them apart from other nodes. In this case, on each k8s node we may need to setup hostname and DNS name
- Edit
/etc/hostname
and set preferredhostname
, ex:kub1
:
sudo vim /etc/hostname
- Edit
/etc/hosts
and set preferred DNS name, ex:kub1
:
sudo vim /etc/hosts
Ensure curl
is available
sudo apt-get update
sudo apt-get install -y apt-transport-https curl
Add repo key
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
Add k8s repo
sudo bash -c "echo 'deb http://apt.kubernetes.io/ kubernetes-xenial main' >> /etc/apt/sources.list.d/kubernetes.list"
sudo apt update
Install k8s:
Install Docker
to run containers:
sudo apt install -y docker.io # install docker container runtime
Install k8s components. This step may be different in case of k8s version you'd like to have
- Latest version
sudo apt install -y kubernetes-cni kubectl kubelet kubeadm # install k8s components
- Specific version, say
1.10.x
sudo apt install -y kubernetes-cni=0.6.0-00
sudo apt install -y kubectl=1.10.0-00
sudo apt install -y kubelet=1.10.0-00
sudo apt install -y kubeadm=1.10.0-00
- Specific version, say
1.11.x
sudo apt install -y kubernetes-cni=0.6.0-00
sudo apt install -y kubectl=1.11.0-00
sudo apt install -y kubelet=1.11.0-00
sudo apt install -y kubeadm=1.11.0-00
sudo cat <<EOF > /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-x86_64
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kube*
EOF
Set SELinux in permissive mode (effectively disabling it). This is required to allow containers to access the host filesystem.
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
systemctl enable --now kubelet
END OF CentOS setup, continue.
Kubernetes requires to have swap turned off, so let's specify this
sudo vim /etc/rc.local
Insert into rc.local
swapoff -a
Insert kubectl
autocomplete script - very useful feature, just press tab
while editing kubectl
command and see what autocomplete can do.
echo "source <(kubectl completion bash)" >> ~/.bashrc
sudo reboot
On a Master node init kubernetes cluster with default settings as:
sudo kubeadm init --pod-network-cidr=10.244.0.0/16
Or, in case you'd like to setup specific Kubernetes version or have issues with preflight system versification:
sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --kubernetes-version=1.10.0
sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --kubernetes-version=1.10.0 --ignore-preflight-errors=SystemVerification
sudo kubeadm init --pod-network-cidr=10.244.0.0/16 --ignore-preflight-errors=SystemVerification
This command may take a while to complete. In case of success, we'll see something like:
Your Kubernetes master has initialized successfully!
To start using your cluster, you need to run the following as a regular user:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
https://kubernetes.io/docs/concepts/cluster-administration/addons/
You can now join any number of machines by running the following on each node
as root:
kubeadm join 192.168.74.149:6443 --token gonf7n.0w7x9huih0gbqcsj --discovery-token-ca-cert-hash sha256:3871b941076a8b6524bfb5407a4e6315a2663bbdb908986a8e982805b7b82f37
Copy and save 'join command'
sudo kubeadm join 192.168.74.149:6443 --token gonf7n.0w7x9huih0gbqcsj --discovery-token-ca-cert-hash sha256:3871b941076a8b6524bfb5407a4e6315a2663bbdb908986a8e982805b7b82f37
And we would like to fetch config
file from /etc/kubernetes/admin.conf
to your local $HOME/.kube
folder on master node, so it can easily be propagated further to users.
Copy k8s config file This can be done with SSH in case you'd like to access k8s cluster from other machine:
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
After that, you can easily get config
from master node with scp
as:
scp <MASTER_NODE>:/home/<USER>/.kube/config ~/.kube/config
Note the following lines reported by kubeadm init
command:
[mark-control-plane] Marking the node kubeadm-master as control-plane by adding the label "node-role.kubernetes.io/master=''"
[mark-control-plane] Marking the node kubeadm-master as control-plane by adding the taints [node-role.kubernetes.io/master:NoSchedule]
This means that master
node has label node-role.kubernetes.io/master=''
and taint node-role.kubernetes.io/master:NoSchedule
.
With such a taint master node will not run any pods. So, in case we'd like to have pods running on all nodes of k8s cluster - including master - we need to clear this taint.
List taints on nodes in JSON form
kubectl get nodes -o json | jq .items[].spec
{
"podCIDR": "10.244.0.0/24",
"taints": [
{
"effect": "NoSchedule",
"key": "node-role.kubernetes.io/master"
},
{
"effect": "NoSchedule",
"key": "node.kubernetes.io/not-ready"
}
]
}
In yaml form
kubectl get nodes -o yaml
and see
labels:
beta.kubernetes.io/arch: amd64
beta.kubernetes.io/os: linux
kubernetes.io/hostname: kub1
node-role.kubernetes.io/master: ""
taints:
- effect: NoSchedule
key: node-role.kubernetes.io/master
By default, your cluster will not schedule pods on the master. Clear taint with:
kubectl taint nodes --all node-role.kubernetes.io/master-
Assign cluster-admin
to kube-system:default
account
kubectl create clusterrolebinding add-on-cluster-admin --clusterrole=cluster-admin --serviceaccount=kube-system:default
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/Documentation/kube-flannel.yml
It'll take some time so setup networking and after several minutes we'll have k8s cluster of one node ready:
kubectl get node
NAME STATUS ROLES AGE VERSION
kub1 Ready master 16m v1.13.4
Now we can setup k8s on other nodes.
Join node into k8s cluster with join
command, saved earlier
sudo kubeadm join 192.168.74.149:6443 --token gonf7n.0w7x9huih0gbqcsj --discovery-token-ca-cert-hash sha256:3871b941076a8b6524bfb5407a4e6315a2663bbdb908986a8e982805b7b82f37
We should see something like:
This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.
FETCH TOKEN IN CASE OLD IS BAD sudo kubeadm token create
kubectl get node
NAME STATUS ROLES AGE VERSION
kub1 Ready master 56m v1.13.4
kub2 NotReady <none> 31s v1.13.4
Give it some time to setup
NAME STATUS ROLES AGE VERSION
kub1 Ready master 56m v1.13.4
kub2 Ready <none> 70s v1.13.4
kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v1.10.1/src/deploy/recommended/kubernetes-dashboard.yaml
=====================================
sudo vim /etc/rc.local swapoff -a
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add -
sudo vim /etc/apt/sources.list.d/kubernetes.list
deb http://apt.kubernetes.io/ kubernetes-xenial main
sudo apt update
sudo apt install -y docker.io kubelet kubeadm kubernetes-cni ceph-common python
vim ~/.bashrc source <(kubectl completion bash)
probably reboot
Download kops
curl -Lo kops https://github.com/kubernetes/kops/releases/download/$(curl -s https://api.github.com/repos/kubernetes/kops/releases/latest | grep tag_name | cut -d '"' -f 4)/kops-linux-amd64
chmod +x ./kops
mv kops ~/bin/kops
kops
store state of the cluster it manages in its own storage. We have two options where to keep cluster state:
- either locally (in files) or
- in S3 storage.
In case of S3 stroage, it is important to setup S3 permissions to control access to the S3 bucket.
Let’s use altinity-kops-state-store
as the S3 bucket name. Create this bucket either in GUI or with CLI tool:
aws s3api create-bucket --bucket altinity-kops-state-store --region us-east-1
Specify bucket to be used as storage to kops
:
export KOPS_STATE_STORE=s3://altinity-kops-state-store
and then kops
will use this S3 bucket as default storage.
Specify and export AWS_PROFILE
env var which references section in ~/.aws/credentials
file with aws_access_key_id
and aws_secret_access_key
. Example of the section:
[altinity]
aws_access_key_id = XXX
aws_secret_access_key = YYY
So in our case AWS_PROFILE
env var would point to altinity
section and we have the whole statement as:
export AWS_PROFILE=altinity
Sidenote If you don't have access keys, you can create them from the AWS Management Console
- Choose IAM in AWS services
- Choose Users in navigation panel
- Choose the name of the user whose access keys you want to create
- Choose Security credentials tab
- Choose Create access key button
- Copy or download access keys to be used in profile
Now, we are ready to manage clusters!
More docs on how to setup profile and users: https://github.com/kubernetes/kops/blob/master/docs/aws.md
If you are using Kops 1.6.2 or later, then DNS configuration is optional.
Instead, a gossip-based cluster can be easily created.
The only requirement to trigger this is to have the cluster name end with .k8s.local
.
For test run it is sufficient to have .k8s.local
domain.
Otherwise setup DNS configuration
For a gossip-based cluster, make sure the name ends with .k8s.local
Create cluster:
kops create cluster --zones=us-east-1a dev.altinity.k8s.local
List clusters:
kops get cluster
Edit cluster:
kops edit cluster dev.altinity.k8s.local
Edit node instance group - specify node parameters (RAM, CPU, etc):
kops edit ig --name=dev.altinity.k8s.local nodes
Edit your master instance group - specify master node parameters (RAM, CPU, etc):
kops edit ig --name=dev.altinity.k8s.local master-us-east-1a
Apply/update cluster with:
kops update cluster dev.altinity.k8s.local --yes
The cluster access configuration was written to ~/.kube/config
, so kubectl
can access new cluster.
kubectl get nodes
Validate cluster with:
kops validate cluster
Install addons as described here
Delete cluster:
kops delete cluster dev.altinity.k8s.local --yes
Create additional instance group Need to:
- Add new subnet
- Add ig into subnet
# add subnet as
- cidr: 172.20.64.0/19
name: us-east-1b
type: Public
zone: us-east-1b
# add ig to subnet
kops create ig --subnet=us-east-1b nodes3
kops update cluster dev.altinity.k8s.local
kops update cluster dev.altinity.k8s.local --yes
Create Cluster: Simple cluster:
kops create cluster --zones=us-east-1a --yes dev.altinity.k8s.local
kubectl taint nodes --all node-role.kubernetes.io/master-
Specify Kubernetes version:
kops create cluster --kubernetes-version 1.12.6 --cloud=aws --zones=us-east-1a --yes dev.altinity.k8s.local
Additional options:
kops create cluster \
--kubernetes-version 1.12.6 \
--zones us-east-1a,us-east-1b,us-east-1c \
--node-count 3 \
--node-size t2.medium \
--master-zones us-east-1a,us-east-1b,us-east-1c \
--master-count 3 \
--master-size t2.micro \
--yes \
dev.altinity.k8s.local
even more options:
kops create cluster \
--name dev.altinity.k8s.local \
--cloud aws \
--master-size m4.large \
--master-zones=us-east-1b,us-east-1c,us-east-1d \
--node-size m4.xlarge \
--zones=us-east-1a,us-east-1b,us-east-1c,us-east-1d,us-east-1e,us-east-1f \
--node-count=3 \
--kubernetes-version=1.11.6 \
--vpc=vpc-1234567\
--network-cidr=10.0.0.0/16 \
--networking=flannel \
--authorization=RBAC \
--ssh-public-key="~/.ssh/kube_aws_rsa.pub" \
--yes
Delete Cluster:
kops delete cluster dev.altinity.k8s.local --yes
Delete instance group
kops delete ig --name=dev.altinity.k8s.local nodes --yes
Update Kubernetes version
- Edit cluster proporties as
kops edit cluster dev.altinity.k8s.local
Find kubernetesVersion
, and let' change it to, say
kubernetesVersion: 1.12.10
- Now we can take a look on changes planned to be made as:
kops update cluster dev.altinity.k8s.local
and apply changes on cluster proporties as:
kops update cluster dev.altinity.k8s.local --yes
At this point we have cluster's specification updated, but we also need to run updates on each node(s) as well.
- Take a look on what nodes has to be updated as
kops rolling-update cluster dev.altinity.k8s.local
We'll see something like :
NAME STATUS NEEDUPDATE READY MIN MAX NODES
master-us-east-1a NeedsUpdate 1 0 1 1 1
nodes NeedsUpdate 2 0 2 2 2
And we can apply rolling update as:
kops rolling-update cluster dev.altinity.k8s.local --yes
This command will drain nodes, update Kubernetes software, etc. This command can take quite long - something about 10 min per each node.
SSH into node
kubectl get node -o wide
Take a look into EXTERNAL IP column. This IP is accessible with SSH and RSA key. We can directly specify RSA key in case there are many of them or just ssh [email protected]
in case there is only one
ssh -i ~/.ssh/id_rsa [email protected]
Username - admin@
in this case - depends on guest OS and would be admin
for debian and centos
for centos.
In case you'd like to remove a node from service use kubectl drain
. This will safely evict all pods from a node. After drain completed, node can be safely maintained.
All pods will be gracefully terminated with respect to PodDistributionBudgets.
Choose node to drain:
kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-172-20-34-156.ec2.internal Ready master 46d v1.10.12
ip-172-20-41-19.ec2.internal Ready node 46d v1.10.12
ip-172-20-59-111.ec2.internal Ready node 46d v1.10.12
Let it be ip-172-20-41-19.ec2.internal
kubectl drain ip-172-20-41-19.ec2.internal
Drain command is clever enough not to delete local data. So you can see the following report in case some pods have loca data on the node:
node/ip-172-20-41-19.ec2.internal cordoned
error: unable to drain node "ip-172-20-41-19.ec2.internal", aborting command...
There are pending nodes to be drained:
ip-172-20-41-19.ec2.internal
error: pods with local storage (use --delete-local-data to override): grafana-68cd9ff6c5-jxsxz, prometheus-prometheus-0
This is normal, Pods were not terminated and Node is just excluded from scheduling new Pods on it:
kubectl get node
NAME STATUS ROLES AGE VERSION
ip-172-20-41-19.ec2.internal Ready,SchedulingDisabled node 46d v1.10.12
and no any Pods are evicted from this Node:
kubectl get all -o wide -n replminpv
NAME READY STATUS RESTARTS AGE IP NODE
pod/chi-83898a64ab-1-0 1/1 Running 0 46d 100.96.2.11 ip-172-20-59-111.ec2.internal
pod/chi-83898a64ab-2-0 1/1 Running 0 46d 100.96.1.11 ip-172-20-41-19.ec2.internal
After node maintenace is completed, run
kubectl uncordon ip-172-20-41-19.ec2.internal
to return node back to service
Get eksctl
binary
curl --silent --location "https://github.com/weaveworks/eksctl/releases/download/latest_release/eksctl_$(uname -s)_amd64.tar.gz" | tar xz -C /tmp
mv -v /tmp/eksctl ~/bin
Check eksctl
is available
eksctl version
[ℹ] version.Info{BuiltAt:"", GitCommit:"", GitTag:"0.1.33"}
Ok, eksctl
is available! Now time to get aws-iam-authenticator
curl --silent --location "https://github.com/kubernetes-sigs/aws-iam-authenticator/releases/download/v0.4.0/aws-iam-authenticator_0.4.0_$(uname -s)_amd64" -o /tmp/aws-iam-authenticator
chmod a+x /tmp/aws-iam-authenticator
mv /tmp/aws-iam-authenticator ~/bin
Ensure command
in ~/.kube/config
is specified as:
command: aws-iam-authenticator
Simple cluster management
eksctl create cluster --name=ekscluster1 --nodes=3 --node-ami=auto --region=us-east-1
eksctl get cluster --name=ekscluster1 --region=us-east-1
eksctl delete cluster --name=ekscluster1 --region=us-east-1
Advanced cluster management options:
eksctl create cluster \
--name testcluster \
--version 1.12 \
--region us-west-2 \
--node-type t3.medium \
--nodes 3 \
--nodes-min 1 \
--nodes-max 4 \
--node-ami auto
eksctl get cluster --name=testcluster --region=us-west-2
eksctl delete cluster --name=testcluster --region=us-west-2
For all available options see:
eksctl create cluster --help
kubectl get node
NAME STATUS ROLES AGE VERSION
ip-192-168-17-77.ec2.internal Ready <none> 19m v1.12.7
ip-192-168-25-67.ec2.internal Ready <none> 19m v1.12.7
ip-192-168-40-148.ec2.internal Ready <none> 18m v1.12.7
Amazon EKS worker nodes run in your AWS account and connect to your cluster's control plane via the API server endpoint and a certificate file that is created for your cluster.
Instance type m5.large
is used by default for worker nodes. Instance type can be specified as --node-type t3.medium
param for eksctl create cluster
command.
A special Worker group used to launch worker nodes can be created with:
eksctl create nodegroup \
--cluster testcluster \
--version auto \
--name testcluster-workers \
--node-type t3.medium \
--node-ami auto \
--nodes 3 \
--nodes-min 1 \
--nodes-max 4
source <(eksctl completion bash)
EKS cluster is specified by .yaml
file. Let's download template
wget https://eksworkshop.com/eksctl/launcheks.files/eksworkshop.yml.template