:::success
These instructions provide guidance for deploying a web server with two worker nodes and load balancing managed by Kubernetes.
:::
Kubernetes installation
---
To install Kubernetes (k8s) on Ubuntu, you can follow these steps:
Update your system:
```
sudo apt update
sudo apt upgrade -y
```
Disable swap memory:
```
sudo swapoff -a
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
```
Reboot after modify the /etc/fstab config.
```
sudo reboot
```
Make sure your 6443 port is not used (k8s use 6443 as default).
```
nc -v 127.0.0.1 6443
nc: connect to 127.0.0.1 port 6443 (tcp) failed: Connection refused
```
Install Docker:
```
sudo apt-get update
sudo apt-get install \
ca-certificates \
curl \
gnupg \
lsb-release
```
```
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
```
```
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-compose-plugin
```
Start docker
```
sudo service docker start
```
check docker status ``sudo docker info``
Add your user name to docker user group so you can use ``docker info`` without sudo.
```
sudo groupadd docker
sudo usermod -aG docker $USER
```
Re-login or reboot to take effect.
These instructions are copied from https://ithelp.ithome.com.tw/articles/10291081.
Set docker Cgroup driver to systemd.
```
sudo bash -c "cat > /etc/docker/daemon.json <<EOF
{
\"exec-opts\": [\"native.cgroupdriver=systemd\"]
}
EOF
"
```
Restart docker and check status.
```
sudo systemctl restart docker
docker info | grep Cgroup
```
Enable and start the Docker service:
```
sudo systemctl enable docker
sudo systemctl start docker
```
You should see
```
Cgroup Driver: systemd
Cgroup Version: 2
```
Install cri-dockerd (for ubuntu 22.04 jammy)
```
wget https://github.com/Mirantis/cri-dockerd/releases/download/v0.3.4/cri-dockerd_0.3.4.3-0.ubuntu-jammy_amd64.deb
sudo dpkg -i cri-dockerd_0.3.4.3-0.ubuntu-jammy_amd64.deb
```
Check if the installation is successful.
```
cri-dockerd --help
```
Reload service and check status.
```
sudo systemctl daemon-reload
sudo systemctl enable cri-docker.service
sudo systemctl enable --now cri-docker.socket
sudo systemctl status cri-docker.socket
```
Start install k8s.
Download the Kubernetes apt repository key:
```
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor | sudo tee /usr/share/keyrings/kubernetes-archive-keyring.gpg >/dev/null
```
Add the Kubernetes apt repository:
```
echo "deb [signed-by=/usr/share/keyrings/kubernetes-archive-keyring.gpg] https://apt.kubernetes.io/ kubernetes-xenial main" | sudo tee /etc/apt/sources.list.d/kubernetes.list
```
Update repository
``sudo apt-get update``
Install Kubernetes components (kubelet, kubeadm, kubectl):
```
sudo apt-get install -y kubelet kubeadm kubectl
sudo apt-mark hold kubelet kubeadm kubectl
```
# Follow this article to set up your k8s cluster.
https://ithelp.ithome.com.tw/articles/10291343
## kubeadm init on master node
sudo kubeadm init \
--apiserver-advertise-address=192.168.1.221 \
--pod-network-cidr=10.244.0.0/16 \
--cri-socket /var/run/cri-dockerd.sock \
--service-cidr=10.96.0.0/12
```
當你的主機網段是 192.168.1.x,你必須確保 Kubernetes 使用的網段不與它衝突。以下是基於你的新網段的建議設定值:
apiserver-advertise-address:這應該是你主機的 IP 地址。在這種情況下,它應該是 192.168.1.221。
pod-network-cidr:為你的 pods 選擇一個不同的網段。如果你的主機在 192.168.1.x,那麼你可能希望選擇像 10.244.0.0/16 這樣的完全不同的 CIDR。
service-cidr:這是用於 Kubernetes 服務的 IP 地址。選擇一個不同的 CIDR,例如 10.96.0.0/12。
```
wget https://raw.githubusercontent.com/flannel-io/flannel/master/Documentation/kube-flannel.yml
vim kube-flannel.yml and make sure the Network CIDR is same as pod-network-cidr you used in kubeadm init.
```json
net-conf.json: |
{
"Network": "10.244.0.0/16",
"Backend": {
"Type": "vxlan"
}
}
```
kubectl apply -f kube-flannel.yml
Check the flannel pods is running.
```
ubuntu@ubuntu:~/app$ kubectl get pods -n kube-flannel
NAME READY STATUS RESTARTS AGE
kube-flannel-ds-qfjgx 1/1 Running 0 2m5s
```
# Deploy nginx-controller
```
kubectl create namespace ingress-nginx
wget -O deploy-ingress-nginx.yaml https://raw.githubusercontent.com/kubernetes/ingress-nginx/controller-v1.0.0/deploy/static/provider/cloud/deploy.yaml
kubectl apply -f deploy-ingress-nginx.yaml
```
kubectl get services -n ingress-nginx
```
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
ingress-nginx-controller LoadBalancer 10.105.132.4 <pending> 80:30388/TCP,443:30966/TCP 16s
ingress-nginx-controller-admission ClusterIP 10.100.138.171 <none> 443/TCP 16s
```
You need to fix the external-ip pending problem if you're not in a cloud enviroment.
To make LoadBalancer (ingress-nginx) work, you must patch the externalIP.
```
kubectl patch svc <svc-name> -n <namespace> -p '{"spec": {"type": "LoadBalancer", "externalIPs":["192.168.1.221"]}}'
```
for example
```
kubectl patch svc ingress-nginx-controller -n ingress-nginx -p '{"spec": {"type": "LoadBalancer", "externalIPs":["192.168.1.221"]}}'
```
# Important!
If you want to run pods on master node, must remove
kubectl taint nodes <NODE_NAME> node-role.kubernetes.io/control-plane:NoSchedule-
use kubectl get nodes to get <NODE_NAME>.
kubectl taint nodes ddbrothers node-role.kubernetes.io/control-plane:NoSchedule-
# Deploy command for bruce:
## gpt backend
### create namespace
kcl create namespace gpt
### deploy pv
make sure the path in yaml exists
e.g."/data/k8s-pv/gpt-postgresql"
and run :
kubectl apply -f /home/ubuntu/k8s_config/gpt-pv.yaml
kubectl get pv # should see the status of pv is `Available` or `Bound`
If the pv status is not good, check the nodeAffinity setting in gpt-pv.yaml, the nodeAffinity may configured to deploy the pv to a specify node.
If you have to delete PV or PVC and re apply, make sure you have a backup data.
### deploy db and web api
#### 視情況註解yaml中的node selector
kubectl apply -f ./DB/deployment.yaml
kubectl apply -f ./Deployment/deployment.yaml
### use port forwarding to test the db and api
kubectl port-forward pods/db-658785646d-rlcqv 35432:5432 -n gpt
kubectl port-forward deployments/gpt-backend 8000:8000 -n gpt
## ddb
kcl create namespace ddb
### deploy pv
make sure the path in yaml exists
e.g.`/data/k8s-pv/ddb-postgresql` and `/data/k8s-pv/ddb-odoo`
and run :
kubectl apply -f /home/ubuntu/k8s_config/ddb-pv.yaml
kubectl get pv # should see the status of pv is `Available` or `Bound`
### label the node to match yaml file
By default, the ddb service use nodeSelector below:
nodeSelector:
node-key: node-ddb
Make sure the desired node is labeled to match the node selector.
#### use this command
kubectl label nodes ddbrothers node-key=node-ddb
### deploy the config map
#### check the settings in the config map and then apply
kubectl apply -f /home/ubuntu/app/odoo-ddb/configMap.yaml
#### if the config map is not exists, find a configMap.example.yaml at the same folder or git repo.
### deploy db and web api
kubectl apply -f /home/ubuntu/app/odoo-ddb/deployment.yaml
kubectl get pv # should see the status of pv is `Available` or `Bound`
### use port forwarding to test the db and api
kubectl port-forward pods/db-658785646d-rlcqv 35432:5432 -n gpt
kubectl port-forward deployments/gpt-backend 8000:8000 -n gpt
## Let's Encrypt
### 安裝 CustomResourceDefinitions
cd ~/k8s_config
mkdir cert-manager
cd cert-manager
wget https://github.com/jetstack/cert-manager/releases/download/v1.7.1/cert-manager.crds.yaml
kubectl apply -f cert-manager.crds.yaml
### 創建 namespace
kubectl create namespace cert-manager
### 部署 cert-manager
wget https://github.com/jetstack/cert-manager/releases/download/v1.7.1/cert-manager.yaml
kubectl apply -f cert-manager.yaml
### 設置 Let's Encrypt 的 ClusterIssuer
#### 建立issuer
這個檔案應該在github k8s_config repo
但要檢查其中的email設定
kubectl apply -f ./letsencrypt-issuer.yaml
#### 建立每一個site專用的憑證
這個檔案應該在github k8s_config repo
kubectl apply -f birdeo-certs.yaml
#### 重新部屬 gpt web api
其中的ingress tls設定的secretName必須和前面birdeo-certs.yaml中設定的相同
kubectl apply -f /home/ubuntu/app/project-gpt-backend/Deployment/deployment.yaml
#### 重新部屬 ddb web api
# 修改gpt-backend部屬的node到birdeonode2
### 停止gpt namespace下的所有服務
kubectl scale deployment gpt-backend --replicas=0 -n gpt
kubectl scale deployment db --replicas=0 -n gpt
### 備份pv對應的folder
sudo cp -r /data/k8s-pv/gpt-postgresql /path/to/backup/dest
### 刪除pvc和pv
kcl delete pvc postgres-data-pvc
kcl delete pv postgresql-gpt-pv
### 將node2加入cluster
進入node2, `ssh ubuntu@192.168.1.222`
使用kubeadm join將node2加入cluster之後
### 將birdeonode2 標記為node-key = birdeonode2
`kcl label nodes birdeonode2 node-key=birdeonode2`
### 設定pv部屬在birdeonode2
設定gpt-pv.yaml的nodeAffinity, 使pv部屬在node 2
```
storageClassName: local-storage
local:
path: /data/k8s-pv/gpt-postgresql
nodeAffinity:
required:
nodeSelectorTerms:
- matchExpressions:
- key: node-key
operator: In
values:
- birdeonode2
```
#### 部屬pv
`kcl apply -f /home/ubuntu/k8s_config/gpt-pv.yaml`
同樣用 `kcl get pv` 檢查 pv 狀態是否 Available
### DB:設定pvc and service 部屬在 birdeonode2
修改 /home/ubuntu/app/project-gpt-backend/DB/deployment.yaml
Deployment增加
```
spec:
template:
spec:
nodeSelector:
node-key: birdeonode2
```
pvc根據名稱使用指定的pv不需要設定nodeSelector
```
spec:
volumeName: postgresql-gpt-pv
```
修改後apply即可
`kcl apply -f /home/ubuntu/app/project-gpt-backend/DB/deployment.yaml`
檢查 pod是否部屬到 birdeonode2
`kcl get pods -o wide`
### API:設定部屬到birdeonode2
同DB設定修改yaml
### 設定node selector
vim /home/ubuntu/app/project-gpt-backend/DB/deployment.yaml
設定其中的 node selector
``` spec:
nodeSelector:
node-key: birdeonode2
```
# [STOP] The following instruction is WRONG
Initialize the Kubernetes cluster on the **master node**:
```
sudo kubeadm init
```
**Note down the kubeadm join command** that is displayed at the end of the initialization process. You will need it to join worker nodes to the cluster.
Set up the Kubernetes configuration for the current user:
```
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
```
Install the pod network add-on. For example, you can use Calico:
```
kubectl apply -f https://docs.projectcalico.org/v3.16/manifests/calico.yaml
```
Join worker nodes to the cluster:
On each worker node, run the kubeadm join command that you noted down in step 8.
Verify the cluster status:
```
kubectl get nodes
```
You should see the master node and the joined worker nodes in the output.
That's it! You have successfully installed Kubernetes on Ubuntu.
K8s service configuration
---
If you have only two EC2 instances and want to set up a simple load balancing strategy between them using Kubernetes, you can use a single LoadBalancer Service to distribute traffic to the two instances. Here's an example of how you can set it up:
Create a YAML file for the LoadBalancer Service. Let's name it loadbalancer.yaml:
```
apiVersion: v1
kind: Service
metadata:
name: my-load-balancer
spec:
type: LoadBalancer
selector:
app: my-web-app
ports:
- protocol: TCP
port: 80
targetPort: 8080
```
In this example, the Service named my-load-balancer will balance traffic to the Pods labeled with app: my-web-app. Adjust the ports as needed.
Create a YAML file for the Pod on the first EC2 instance. Let's name it instance-1.yaml:
```
apiVersion: v1
kind: Pod
metadata:
name: instance-1
labels:
app: my-web-app
spec:
containers:
- name: web-server
image: my-web-server-image:latest
ports:
- containerPort: 8080
```
Replace instance-1 with a suitable name and adjust the container image and port based on your web server setup.
Create a YAML file for the Pod on the second EC2 instance. Let's name it instance-2.yaml:
```
apiVersion: v1
kind: Pod
metadata:
name: instance-2
labels:
app: my-web-app
spec:
containers:
- name: web-server
image: my-web-server-image:latest
ports:
- containerPort: 8080
```
Replace instance-2 with a suitable name and adjust the container image and port as needed.
Apply the YAML files to create the LoadBalancer Service and the Pods:
```
kubectl apply -f loadbalancer.yaml
kubectl apply -f instance-1.yaml
kubectl apply -f instance-2.yaml
```
Once applied, the LoadBalancer Service will distribute traffic to the Pods running on the two EC2 instances.
## memory monitor tool
install ps_mem tool
```sudo pip install ps_mem```
add \$HOME/.local/bin to PATH by modify ~/.bashrc
``vi ~/.bashrc``
add the following line in the bottom of ~/.bashrc
``export PATH="$PATH:$HOME/.local/bin"``
apply the ~/.bashrc again
``source ~/.bashrc``
now you can use `sudo ps_mem` to get a detail memory usage info.
```
Private + Shared = RAM used Program
148.0 KiB + 16.5 KiB = 164.5 KiB gsd-xsettings
36.6 MiB + 11.5 KiB = 36.6 MiB Xwayland
70.7 MiB + 156.5 KiB = 70.9 MiB dockerd
122.9 MiB + 31.1 MiB = 154.0 MiB node (4)
149.9 MiB + 26.0 MiB = 175.8 MiB gnome-shell
---------------------------------
1.0 GiB
=================================
```
1. delete etcd
sudo rm -rf /var/lib/etcd/member
2. backup data
sudo cp -r /data/k8s-pv /data/k8s-pv-backup
3. reset k8s
sudo kubeadm reset --cri-socket=unix:///var/run/cri-dockerd.sock
and got this
```
ubuntu@ddbrothers:~$ sudo kubeadm reset --cri-socket=unix:///var/run/cri-dockerd.sock
[reset] Reading configuration from the cluster...
[reset] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
W0520 21:58:15.625280 65850 reset.go:106] [reset] Unable to fetch the kubeadm-config ConfigMap from cluster: failed to get config map: Get "https://192.168.1.221:6443/api/v1/namespaces/kube-system/configmaps/kubeadm-config?timeout=10s": dial tcp 192.168.1.221:6443: connect: connection refused
W0520 21:58:15.625390 65850 preflight.go:56] [reset] WARNING: Changes made to this host by 'kubeadm init' or 'kubeadm join' will be reverted.
[reset] Are you sure you want to proceed? [y/N]: y
[preflight] Running pre-flight checks
W0520 21:58:30.641167 65850 removeetcdmember.go:106] [reset] No kubeadm config, using etcd pod spec to get data directory
[reset] Stopping the kubelet service
[reset] Unmounting mounted directories in "/var/lib/kubelet"
[reset] Deleting contents of directories: [/etc/kubernetes/manifests /var/lib/kubelet /etc/kubernetes/pki]
[reset] Deleting files: [/etc/kubernetes/admin.conf /etc/kubernetes/kubelet.conf /etc/kubernetes/bootstrap-kubelet.conf /etc/kubernetes/controller-manager.conf /etc/kubernetes/scheduler.conf]
The reset process does not clean CNI configuration. To do so, you must remove /etc/cni/net.d
The reset process does not reset or clean up iptables rules or IPVS tables.
If you wish to reset iptables, you must do so manually by using the "iptables" command.
If your cluster was setup to utilize IPVS, run ipvsadm --clear (or similar)
to reset your system's IPVS tables.
The reset process does not clean your kubeconfig files and you must remove them manually.
Please, check the contents of the $HOME/.kube/config file.
ubuntu@ddbrothers:~$
```