Docker

在 Ubuntu 18.04 上安裝 Docker CE

安裝環境是在 Ubuntu 18.04 上。

安裝 Docker CE

docker.io 是 docker 的舊版本,如果先前有安裝要移除舊版本:

1
sudo apt-get remove docker docker-engine docker.io containerd runc

安裝相關套件:

1
2
3
4
5
6
sudo apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common

匯入 docker apt repository:

1
2
3
4
5
6
7
8
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"

sudo apt-get update

安裝 docker ce:

1
sudo apt-get install -y docker-ce docker-ce-cli containerd.io

建立 daemon:

1
2
3
4
5
6
7
8
9
10
11
12
13
# root
sudo cat > /etc/docker/daemon.json <<EOF
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2"
}
EOF

mkdir -p /etc/systemd/system/docker.service.d

啟用 Docker:

1
2
sudo systemctl start docker.service
sudo systemctl enable docker.service

加入使用者權限,加完後記得要重新開啟終端機:

1
2
sudo groupadd docker
sudo usermod -aG docker $USER

安裝完成

1
docker --version

Reference

Bare Metal 在 Ubuntu 上安裝 Kubernetes

Docker

在安裝 Kubernetes 前要先安裝好 Docker,可以參考這篇:

Kubeadm

kubeadm 負責管理節點,可以透過方便的指令將電腦加入 cluster,在這裡我們先定義:

  • Master:代表主結點,負責控制與分發任務
  • Node:代表子結點,負責執行 Master 所分發的任務

[Master, Node] 安裝 Kubeadm 需要 root 權限:

1
sudo su -

[Master, Node] 安裝 kubeadm:

1
2
3
4
curl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key add -
echo "deb http://apt.kubernetes.io/ kubernetes-xenial main" > /etc/apt/sources.list.d/kubernetes.list
apt update
apt install -y kubeadm

apt 安裝 kubeadm 完後會連同 kubelet 跟 kubectl 一起安裝。

[Master]Master 節點上初始化 Kubernetes:

1
kubeadm init --pod-network-cidr 10.244.0.0/16

因為我們是使用 flannel,所以必須加上 --pod-network-cidr

我們這邊選擇 flannel 的是因為 flannel 支援 arm。

如果要透過 WIFI 連接網路的話,需要加上 --apiserver-advertise-address=<wifi-ip-address> 參數到 kubeadm init 指令上。

執行 kubeadm init 之後會有一行 kubeadm join,如果弄丟的話,可以執行下面指令獲得:

1
kubeadm token create --print-join-command

[Node] 然後把其他的 node 加進來:

1
2
kubeadm join 192.168.0.11:6443 --token 3c564d.6q2we53btzqmf1ew \
--discovery-token-ca-cert-hash sha256:a5480dcd68ec2ff27885932ac80d33aaa0390d295d4834032cc1eb554de3d5d2

[Master, Node] 離開 root

1
exit

Kubectl

[Master] 回到使用者模式後執行:

1
2
3
mkdir -p $HOME/.kube
sudo cp -f /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

admin.conf 放置到 ~/.kube/config 就會自動抓取設定檔。

[Master] 安裝 flannel,相關文件在 CoreOS 上:

1
kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/bc79dd1505b0c8681ece4de4c0d86c5cd2643275/Documentation/kube-flannel.yml

[Master] 查看目前節點:

1
2
3
4
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
akiicat Ready master 77m v1.14.1
akiicat-node2 Ready <none> 51s v1.14.1

測試

執行一些簡單的容器:

1
kubectl run kuard --image=gcr.io/kuar-demo/kuard-amd64:blue --replicas=3

查看 pods 是否有在運行

1
2
3
4
5
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
kuard-6cdb64fdcd-7bfgq 1/1 Running 0 17s
kuard-6cdb64fdcd-82mtv 1/1 Running 0 17s
kuard-6cdb64fdcd-rhxp2 1/1 Running 0 17s

使用 LoadBalancer 暴露它:

1
kubectl expose deployment kuard --type=LoadBalancer --port=80 --target-port=8080

查看 Service

1
2
3
4
5
6
7
8
9
10
11
12
$ kubectl describe service/kuard
Name: kuard
...
Type: LoadBalancer
IP: 10.109.141.84
Port: <unset> 8080/TCP
TargetPort: 8080/TCP
NodePort: <unset> 30034/TCP
Endpoints: 10.244.1.5:8080,10.244.1.6:8080,10.244.1.7:8080
Session Affinity: None
External Traffic Policy: Cluster
Events: <none>

使用 curl 連到 pod 的 endpoint:

1
2
3
$ curl 10.244.1.5:8080
Hostname: kuard-1-6cdb64fdcd-7bfgq
...

Trouble Shooting

Swap Error

當你用 root 權限執行 kubeadm init 時,會出現 ERROR Swap 的錯誤:

1
2
3
4
5
6
7
8
9
# kubeadm init --pod-network-cidr 10.244.0.0/16
[init] Using Kubernetes version: v1.14.1
[preflight] Running pre-flight checks
[preflight] WARNING: Couldn't create the interface used for talking to the container runtime: docker is required for container runtime: exec: "docker": executable file not found in $PATH
error execution phase preflight: [preflight] Some fatal errors occurred:
[ERROR FileContent--proc-sys-net-bridge-bridge-nf-call-iptables]: /proc/sys/net/bridge/bridge-nf-call-iptables does not exist
[ERROR FileContent--proc-sys-net-ipv4-ip_forward]: /proc/sys/net/ipv4/ip_forward contents are not set to 1
[ERROR Swap]: running with swap on is not supported. Please disable swap
[preflight] If you know what you are doing, you can make a check non-fatal with `--ignore-preflight-errors=...`

如果啟用 swap 的話,當你記憶體不夠用的時候,OS 會先把暫時沒有用的資料存到硬碟裡,又稱作為 swap out。相反,OS 需要用到剛剛存在硬碟裡的資料,則會把資料再載入回記憶體裡面,又稱作為 swap in。

使用 Kubenetes 的時候需要停用 swap 這個功能:

1
swapoff -a

相關討論在 Github 的 issue 上。

上面的設定在重新開機之後就會失效 swap,要將 swap 完全關掉的話,需編輯 /etc/fstab 這個檔案,將 mount point 在 / 的項目註解掉:

1
2
# /etc/fstab
# UUID=10e56f7b-7b40-4b10-8029-642badc59ce9 / ext4 errors=remount-ro 0 1

exec format error

由於 CPU 有分 Intel 跟 Arm 的架構,這個問題會發生是因為 Docker image files 是基於某個特定的架構。也就是說,在 Intel 上建立的 Docker file 只能在 Intel 上執行;在 Arm32 上建立的 Docker file 只能在 Arm32 上執行。

所以當你使用 kubectl logs 查看某個 pod 出現如下的錯誤時:

1
2
$ kubectl logs pod/kuard-777c5775cd-lg7kc
standard_init_linux.go:207: exec user process caused "exec format error"

確認你的 Docker image 有支援你 CPU 的架構

Stackoverflow 上的討論

Reference

在 Ubuntu 上架設 NFS server

思路

NFS (Network File System) 可以透過網路,讓不同的作業系統,分享個別的檔案。

而我想要在 Ubuntu 上建立 NFS Server,透過 Mac 上的 NFS Client 連上。目前的環境:

  • Ubuntu 18.04: 192.168.0.10
  • Mac OS X Mojave: 192.168.0.20

NFS Server

安裝

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# ubuntu bare metal
sudo apt install -y nfs-kernel-server

# docker container all in one
mkdir -p /tmp/nfs
sudo chown -R nobody:nogroup /tmp/nfs
docker run -d --privileged --restart=always \
-v /tmp/nfs:/nfs \
-e NFS_EXPORT_DIR_1=/nfs \
-e NFS_EXPORT_DOMAIN_1=\* \
-e NFS_EXPORT_OPTIONS_1=rw,insecure,no_subtree_check,all_squash \
-p 111:111 -p 111:111/udp \
-p 2049:2049 -p 2049:2049/udp \
-p 32765-32767:32765-32767 -p 32765-32767:32765-32767/udp \
fuzzle/docker-nfs-server:latest

安裝好之後,會在 /etc 底下會多一個 exports 的檔案,待會我們可以修改這個檔案,來調整想要分享的檔案。

至於 docker 的部分是來自於這個 repo

建立資料夾

我想要把 /tmp/nfs 這個資料夾分享出去,所以先建立這個資料夾:

1
mkdir -p /tmp/nfs

資料夾權限

目前 /tmp/nfs 的權限是 root:root ,第一個 root 是 owner 的權限,第二個 root 是 group 的權限:

1
2
$ ls -la /tmp/nfs
drwxr-xr-x 3 root root 4096 3月 9 22:26 nfs

要把檔案分享出去的話,需要修改資料夾的權限為 nobody:nogroup,且加上 -R 的參數把資料夾底下的所有子資料夾都設為 nobody:nogroup

1
sudo chown -R nobody:nogroup /tmp/nfs

如果後來又新增檔案的話,必須再重新執行一次這一行指令。

否則在之後 mount 的時後會出現 Operation not permitted 的錯誤:

1
mount_nfs: can't mount /tmp/nfs from 192.168.0.10 onto ...: Operation not permitted

設定

修改 /etc/exports

1
sudo vim /etc/exports

然後把想要分享的檔案加入:

1
2
3
4
5
6
7
# /etc/exports
# 格式:
# 在 ubuntu 上想要分享的資料夾 這個 IP 連進來的可以存取這個檔案(選項)
/tmp/nfs 192.168.0.0/24(rw,sync,no_subtree_check,all_squash)

# * 代表任何人都可以連進來
/tmp *(rw,sync,no_subtree_check,all_squash)

至於選項是選擇性填寫的,有很多參數可以選:

  • ro:read only
  • rw:read and write
  • async:此選項允許 NFS Server 違反 NFS protocol,允許檔案尚未存回磁碟之前回覆請求。這個選項可以提高性能,但是有可能會讓 server 崩潰,可能會需要重新啟動 server. 或檔案遺失。
  • sync:只會儲存檔案會磁碟之後才會回覆請求。
  • no_subtree_check:禁用子樹檢查,會有些微的不安全,但在某些情況下可以提高可靠性。
  • secure:請求的 port 必須小於 1024,這個選項是預設的。
  • insecure:請求的 port 不一定要小於 1024。

User ID Mapping 參數:

  • root_squash:將 uid 0 的使用者映射到 nobody 匿名使用者,這個選項是預設的。
  • no_root_squash:關掉 root squash 的選項,這個選項可以使用 root 身份來控制 NFS Server 的檔案。
  • all_squash:所有登入 NFS 的使用者身份都會被壓縮成為 nobody。
  • anonuid and anongid:調整匿名使用者的權限,可以讓所有透過 NFS 修改文件,都看起來是同一個使用者。

更多參數的選項可以參考 LInux exports

重新啟動 Server

1
sudo systemctl restart nfs-kernel-server

檢查

輸入以下的指令,確認使否把檔案加入 NFS Server:

1
2
3
$ sudo exportfs 
/home/akiicat/share
192.168.0.20/8

目前 showmount 的指令會是空的,因為還沒有 NFS Client 連上,如果連上的話,NFS Server 這邊可以使用 showmount 指令查看哪個 Client IP 連過來的:

1
2
$ showmount
x.x.x.x

NFS Client

安裝

這台 Ubuntu 的 IP 是 192.168.0.30

1
2
# ubuntu
sudo apt install -y nfs-common

Mount

我想要跟 share 資料夾做分享,使用 mount 指令將遠端的資料夾 /tmp/nfs 掛載到本地端的資料夾 share

1
2
3
4
5
6
7
# mac
mkdir -p /tmp/nfs
sudo mount -t nfs -o rw,resvport 192.168.0.10:/tmp/nfs /tmp/nfs

# ubuntu
mkdir -p /tmp/nfs
sudo mount 192.168.0.10:/tmp/nfs /tmp/nfs

注意在 mac 上必須加上 -o resvport 的參數,否則會出現 Operation not permitted 的錯誤。

檢查

輸入以下指令檢查是否掛載成功:

1
2
3
4
# mac, ubuntu
$ df -h
...
192.168.0.30:/tmp/nfs 458G 8.3G 426G 2% /tmp/nfs

測試

/tmp/nfs 資料夾內建立 test 檔案:

1
2
# mac, ubuntu
echo "Hello World" > /tmp/nfs/test

是否能成功建立

Unmount

1
2
# mac, ubuntu
sudo umount -f 192.168.0.10:/tmp/nfs