# NASA hw5
## info
學號: 41173058h
學生: 鍾詠傑
## References
- Lab 5Slides:
- https://docs.google.com/presentation/d/1MV_lMUDzkaDGnUFqYSm-p76lKQE4-ECJW5B_JE4_oww/edit#slide=id.g26ba0c57e7f_0_159
- Minikube Documentation:
- https://minikube.sigs.k8s.io/docs/start/
- Ubuntu Console Configuration:
- https://blog.wataash.com/ubuntu_console/
- Manage Docker as a Non-root User:
- https://docs.docker.com/engine/install/linux-postinstall/
- Port Forwarding:
- https://stackoverflow.com/questions/47173463/how-to-access-local-kubernetes-minikube-dashboard-remotely
- Kubernetes Dashboard:
- https://ithelp.ithome.com.tw/m/articles/10195385
- Kubernetes Tutorial:
- https://blog.techbridge.cc/2018/12/01/kubernetes101-introduction-tutorial/
- Translate a Docker Compose File to Kubernetes Resources:
- https://kubernetes.io/docs/tasks/configure-pod-container/translate-compose-kubernetes/
- Tunneling Tools:
- https://tailscale.com/
- Helm Introduction:
- https://ithelp.ithome.com.tw/articles/10238998
- Helm Chart Documentation:
- https://helm.sh/docs/
- Helm Chart for phpMyAdmin:
- https://artifacthub.io/packages/helm/bitnami/phpmyadmin
- Helm Chart for MySQL:
- https://artifacthub.io/packages/helm/bitnami/mysql
## Examples
- Example 1:
- https://github.com/rzrokon/Docker-NGINX-PHP-MySQL-PhpMyadmin/tree/master
- Example 2:
- https://github.com/nanoninja/docker-nginx-php-mysql
<div style="page-break-after:always;"></div>
# Virsh
## 1 安裝VM
設定 ubuntu.qcow2
```
qemu-img create -f qcow2 -o cluster_size=2M ubuntu.qcow2 20G
```
新增一個 Virtual Machine
```bash
virt-install \
--name=41173058h \
--vcpus=2 \
--memory=8192 \
--disk path=/tmp2/41173058h/nasahw5/ubuntu.qcow2,size=20 \
--cdrom=ubuntu.iso \
--os-variant=ubuntu20.04 \
--network=default \
--mac=52:54:00:17:30:58 \
--console pty,target_type=serial \
--graphics vnc,listen=0.0.0.0,password=0910 \
--noautoconsole
```
暫時用vnc安裝linux
`virsh vncdisplay 41173058h`
安裝完成後記得回到 host
`virsh edit 41173058h`
刪除安裝介質區塊
然後重新開機`virsh start 41173058h`
<div style="page-break-after:always;"></div>
### 圖片
virsh list 的輸出畫面(右上)

VM 內開機完成的畫面

VM 內登入後的畫面

VM 內執行 ip a 指令的輸出畫面

失敗時刪除用指令
```
virsh shutdown 41173058h
virsh undefine 41173058h --remove-all-storage
```
<div style="page-break-after:always;"></div>
## 2 開啟 serial console 與 ssh
enable console serial
https://blog.wataash.com/ubuntu_console/
```
sudo vim /etc/default/grub
```
進行以下操作
```
## remove (optional):
# GRUB_TIMEOUT_STYLE=hidden
## change:
# (optional)
# GRUB_TIMEOUT=0
GRUB_TIMEOUT=2
## add:
GRUB_TERMINAL="console serial"
GRUB_SERIAL_COMMAND="serial --speed=115200"
## change:
# GRUB_CMDLINE_LINUX=""
GRUB_CMDLINE_LINUX="console=tty1 console=ttyS0,115200"
```
執行`sudo update-grub`後reboot
回到工作站
```
virsh console 41173058h
```
整台都是工作站,但是左下為console serial

### ssh
在安裝linux時就有安裝openssh 服務了
但是要對VM進行端口轉發,將某個 port 的 ssh 需求導向
VM
https://serverfault.com/a/352598
在工作站進行端口轉發
```
virsh qemu-monitor-command --hmp 41173058h 'hostfwd_add ::3636-:22'
ssh h41173058@ws2.csie.ntu.edu.tw -p 3636
```


<div style="page-break-after:always;"></div>
# docker
## 3. Docker Set Up
在安裝linux時就有安裝openssh 服務了
在這裡避免每次 Docker 都要 sudo
Manage Docker as a non-root user
https://docs.docker.com/engine/install/linux-postinstall/
```
sudo groupadd docker
sudo usermod -aG docker $USER
newgrp docker
docker run hello-world
```
如果未成功就reboot 即可生效
## 截圖
sudo docker version (左上)
與 sudo dockercompose version (左下)

<div style="page-break-after:always;"></div>
## Docker Basics
## 4. 使用 Container 的時機:
- 開發與測試環境的快速搭建和拆卸。
- 微服務架構下的部署與擴展。
- 持續集成/持續交付 (CI/CD) 流程中的自動化測試和部署。
- 需要將應用程式與其相依性打包成獨立的單元。
使用 VM 而非 Container 的時機:
- 需要完全隔離的環境,如安全性要求較高的應用程式。
- 應用程式需要特定的作業系統環境,而非容器化的應用程式。
- 需要運行不同作業系統的應用程式。
<div style="page-break-after:always;"></div>
# 5.
在 Windows 和 macOS 上,container 的效能會比在 Linux 上差,主要原因是因為 Docker 在這些作業系統上需要透過額外的虛擬化層來執行,而這會增加一些額外的開銷,導致效能下降。例如,在 Windows 上,Docker Desktop 使用 Hyper-V 或 WSL 2 來執行 Linux container,而在 macOS 上,Docker Desktop 使用 HyperKit 虛擬機來執行 Linux container。這些額外的虛擬化層會增加系統資源的使用量,並可能導致效能下降。
<div style="page-break-after:always;"></div>
# 6.
(a) `docker stop $(docker ps -aq)`
- 此指令會停止所有正在運行的 container。`docker ps -aq` 用來列出所有 container 的 ID。
(b) `docker rmi $(docker images -aq)`
- 此指令會刪除所有的 image。`docker images -aq` 用來列出所有 image 的 ID。
(c) `docker system prune -af`
- 此指令會刪除所有未被使用的資源,包含 containers, networks, images 與 volume。
(d) `docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' 5b0f1ed0dcb8`
- 此指令會列出 container 的 IP。以提供的 Container ID 為例。
(e) `docker stats --all --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}"`
- 此指令會即時查看當前所有 container 所使用的 CPU 與 Memory。
<div style="page-break-after:always;"></div>
## 7. nginx
```
docker run -d -p 8763:80 --name nginx-1 nginx:1.24.0
curl http://localhost:8763
```
### 截圖
成功的截圖(左上)


:::warning
這邊我使用了一個比較外掛的手段,內網穿透
使用工具為 `tailscale`
https://tailscale.com/
安裝方式
```
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
```

透過內網穿透,避免麻煩的qemu端口轉發,直接對tailscale給的ip當成該機器的localhost就可以在桌機開啟網頁了。
:::
<div style="page-break-after:always;"></div>
## 8
以下指令即可進入
```
docker exec -it nginx-1 /bin/bash
```
(左上)

## 9
以下指令即可查看
```
docker exec nginx-1 cat /etc/nginx/nginx.conf
```
(左上)

<div style="page-break-after:always;"></div>
## 10
在 Dockerfile 中,ENTRYPOINT 和 CMD 是兩個用於設定容器啟動後要執行的指令的指令。它們之間的差異如下:
1. **ENTRYPOINT**:
- 定義容器啟動後要執行的可執行文件或指令。
- 如果在執行容器時指定了指令,則會覆蓋 ENTRYPOINT 中的任何指令。
- 可以將 ENTRYPOINT 視為容器的主要執行程序。
2. **CMD**:
- 定義在執行容器時要執行的默認指令。
- 如果使用者在執行容器時提供了指令,CMD 將被忽略。
- 可以將 CMD 視為 ENTRYPOINT 的默認參數。
以下是一個示例 Dockerfile,展示了如何同時使用 ENTRYPOINT 和 CMD:
```Dockerfile
FROM alpine:latest
# 定義 ENTRYPOINT,指定一個可執行的 shell 腳本
ENTRYPOINT ["/bin/sh", "-c"]
# 定義 CMD,設置默認的參數為一個 echo 指令
CMD ["echo", "Hello, World!"]
```
在這個 Dockerfile 中,我們使用 Alpine Linux 作為基礎映像。ENTRYPOINT 被設置為 /bin/sh -c,這意味著我們將在容器啟動後運行的指令解釋為 shell 腳本。CMD 被設置為 ["echo", "Hello, World!"],這是一個默認的指令,當使用者沒有提供指令時將被執行。
當你建立並運行此 Docker 映像時,如果不提供任何指令,容器將啟動並執行默認的 CMD,即輸出 "Hello, World!"。如果你提供了額外的指令。
例如,如果你運行以下指令:
```bash
docker run my-image
```
這將啟動容器並執行默認的 CMD,結果會輸出:
```
Hello, World!
```
但如果你運行以下指令,提供了一個替代的指令:
```bash
docker run my-image echo "Goodbye, World!"
```
這將覆蓋默認的 CMD,而是執行提供的指令,結果會輸出:
```
Goodbye, World!
```
這展示了 CMD 如何提供一個默認指令,而 ENTRYPOINT 則定義了容器啟動後要執行的程序,但這個程序可以在運行時被替換。
<div style="page-break-after:always;"></div>
## 11.
Docker Compose 是一個用於定義和運行多個 Docker 容器應用程序的工具。它允許使用者使用 YAML 文件定義應用程式的服務、環境變數、網路設置和卷等資源,並且可以使用單個指令來啟動、停止、管理整個應用程式的生命週期。
主要差別:
- Docker 是一個用於建立、部署和執行容器的平台,而 Docker Compose 則是用於定義和管理多個容器應用程式的工具。
- Docker 主要用於單個容器的操作,而 Docker Compose 則用於多個容器之間的聯合操作。
- Docker Compose 可以使用一個 YAML 文件來定義應用程式的配置,包括容器、網路、卷等,而 Docker 需要使用多個指令來操作單個容器。
<div style="page-break-after:always;"></div>
## 12.
(a) 在背景啟動所有服務:
```bash
docker-compose up -d
```
- 此指令會在背景啟動所有在 docker-compose.yml 文件中定義的服務。
(b) 暫停所有服務:
```bash
docker-compose pause
```
- 此指令會暫停所有在 docker-compose.yml 文件中定義的服務。
(c) 刪除所有服務、network 與 volume:
```bash
docker-compose down --volumes
```
- 此指令會停止並刪除所有在 docker-compose.yml 文件中定義的服務,並同時刪除相關的網路和卷。
<div style="page-break-after:always;"></div>
# Application
## 13 sl-apline
```dockerfile
FROM alpine:latest
RUN apk update && \
apk add --no-cache \
git \
make \
ncurses-dev \
gcc \
g++ \
libc-dev \
&& rm -rf /var/cache/apk/*
RUN git clone https://github.com/mtoyoda/sl.git /sl
WORKDIR /sl
RUN make
CMD ["./sl"]
```
```
docker build -t sl .
docker run --rm -it sl
```

<div style="page-break-after:always;"></div>
## 14 MySQL + phpadmin docker compose
```yaml
version: "3"
services:
db:
image: mysql:latest
container_name: 41173058h
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: my_db
MYSQL_PASSWORD: secret
ports:
- "6033:3306"
volumes:
- db_data:/var/lib/mysql
restart: always
networks:
- nasa-net
phpmyadmin:
image: phpmyadmin/phpmyadmin
links:
- db
environment:
PMA_HOST: db
PMA_PORT: 3306
restart: always
ports:
- 8888:80
networks:
- nasa-net
networks:
nasa-net:
volumes:
db_data:
```
```
docker-compose up -d
docker-compose down
```
:::warning
這邊我使用了一個比較外掛的手段,內網穿透
使用工具為 `tailscale`
https://tailscale.com/
安裝方式
```
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
```

透過內網穿透,避免麻煩的qemu端口轉發,直接對tailscale給的ip當成該機器的localhost就可以在桌機開啟網頁了。
:::


<div style="page-break-after:always;"></div>
## 15

以下是 Kubernetes 的基礎元件、每種節點的角色及其基本元件的說明,以及使用 Kubernetes 的好處:
### Kubernetes 基礎元件:
1. **Master Components (控制平面組件):**
- **kube-apiserver**: Kubernetes API 的前端,負責提供 RESTful API 來管理整個 Kubernetes 叢集。
- **kube-controller-manager**: 監控控制器,負責監控集群狀態並根據預期狀態進行集群中的操作。
- **kube-scheduler**: 負責將 Pod 調度到叢集中的節點上,根據各種條件(如資源需求、策略等)選擇適當的節點。
2. **Node Components (工作節點組件):**
- **kubelet**: 在每個節點上運行,負責管理容器的生命週期、掛載卷 (Volumes) 和其他與容器相關的任務。
- **kube-proxy**: 負責在節點上實現 Kubernetes 服務的代理和負載平衡。
- **Container Runtime**: Kubernetes 支援多種容器運行時,如 Docker、containerd 等。
3. **etcd**:
- 分佈式 key-value 存儲系統,用於存儲 Kubernetes 集群的所有配置數據,包括集群狀態、配置和元數據等。
### 叢集中每一種 node 所扮演的角色及其基本元件的作用:
1. **Master Node**:
- 主要負責叢集的控制和管理。
- 基本元件:kube-apiserver、kube-controller-manager、kube-scheduler、etcd。
2. **Worker Node**:
- 在叢集中運行應用程序工作負載。
- 基本元件:kubelet、kube-proxy、Container Runtime。
3. **Pod**:
- 定義:Pod 是 Kubernetes 中最小的可部署單位,它可以包含一個或多個容器,這些容器共享同一個網絡命名空間、IP 地址和資源。
- 特點:
- 共享網絡命名空間:Pod 中的容器共享同一個網絡命名空間,它們可以通過 localhost 直接相互通信。
- 共享存儲:Pod 中的容器可以共享存儲卷 (Volumes),這使得它們可以在同一個 Pod 內共享數據。
- 單獨調度:Pod 作為調度的基本單元,通常會被一起部署到同一個節點上,但 Kubernetes 也支援將不同的 Pod 調度到不同的節點上。
- 角色:
- 在叢集中的節點上運行,Pod 中的容器共享同一個節點的資源和環境。
- 目的:
- 提供一個單元化的調度和管理單位,方便應用程序的部署、管理和擴展。
- 在 Kubernetes 中,Pod 是最基本的部署單元,用於包裝應用程序的相關容器並管理它們的生命週期。每個節點可以運行多個 Pod,這些 Pod 可以包含不同的應用程序或服務,通過 Kubernetes 的調度和管理,實現高效的資源利用和服務部署。
### 使用 Kubernetes 的好處:
1. **自動部署和擴展**:Kubernetes 可以自動部署和擴展應用程序,根據負載和需求動態調整資源。
2. **高可用性**:Kubernetes 提供了高可用性的服務,並能夠自動恢復節點或應用程序失敗。
3. **容錯性**:Kubernetes 具有容錯機制,可以應對節點或應用程序失敗,確保服務持續可用。
4. **彈性伸縮**:Kubernetes 允許彈性伸縮,根據需求動態調整容器實例的數量,以確保資源的有效利用。
5. **服務發現和負載平衡**:Kubernetes 提供了內建的服務發現和負載平衡功能,可以輕鬆地將流量分發到不同的容器實例中。
6. **容器管理**:Kubernetes 提供了豐富的容器管理功能,包括生命周期管理、資源管理、存儲管理等,使容器化應用程序更易於管理和操作。
<div style="page-break-after:always;"></div>
## 16 final
:::danger
以下有不少失敗案例,我會一列舉
最後有成功部屬服務,不過未完成所有要求,希望能給我部分分數
:::
:::info
建立VM空間
```
qemu-img create -f qcow2 -o cluster_size=2M ubuntu2.qcow2 20G
```
建立VM
```bash
virt-install \
--name=G36VM02 \
--vcpus=4 \
--memory=8192 \
--disk path=/tmp2/41173058h/nasahw5/ubuntu2.qcow2,size=20 \
--cdrom=ubuntu.iso \
--os-variant=ubuntu20.04 \
--network=default \
--console pty,target_type=serial \
--graphics vnc,listen=0.0.0.0,password=0910 \
--noautoconsole
```
設定 port fwd
```
virsh qemu-monitor-command --hmp G36VM02 'hostfwd_add ::3600-:22'
```
:::
:::warning
### 失敗手段一
使用 docker-compose 後
再使用自動化YAML configuration file 部署工具:
Translate a Docker Compose File to Kubernetes Resources
https://kubernetes.io/docs/tasks/configure-pod-container/translate-compose-kubernetes/
```yaml
version: '3.7'
services:
nginx:
image: nginx:latest
container_name: nginx-41173058h
ports:
- "8888:80"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
- ./nginx/html:/usr/share/nginx/html
depends_on:
- php
php:
image: php:7-fpm
container_name: php-41173058h
volumes:
- ./php:/var/www/html
ports:
- "7070:80"
depends_on:
- mysql
mysql:
image: mysql:5.7
container_name: mysql-41173058h
environment:
- MYSQL_ROOT_PASSWORD=password
volumes:
- db_data:/var/lib/mysql
ports:
- "6033:3306"
phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: phpmyadmin-41173058h
ports:
- "8080:80"
depends_on:
- mysql
environment:
PMA_HOST: db
PMA_PORT: 3306
PMA_ARBITRARY: 1
volumes:
db_data:
```
:::
失敗原因
沒辦法對 Volume Type 進行自動建立 hostPath,local volume type
```
Volume mount on the host "/home/g36maid/juejin/nginx/conf.d" isn't supported
Volume mount on the host "/home/g36maid/juejin/nginx/html" isn't supported
Volume mount on the host "/home/g36maid/juejin/php" isn't supported
```
:::warning
### 方法二
透過 helm chart 全自動部屬 k8s 與 docker
Helm 是一個管理 Kubernetes 應用程式的套件,透過 Helm Charts 這套系統,可以幫助開發者打包,安裝,升級相關的 Kubernetes 應用程式。
此外, Helm Charts 本身也被設計得很容易去創造,版本控制,分享以及發佈,所以透過 Helm Charts 就可以避免到處 Copy-and-Paste 各式各樣的 Yaml。
https://artifacthub.io/packages/helm/bitnami/phpmyadmin
https://artifacthub.io/packages/helm/bitnami/mysql
有成功部屬 MySQL + phpmyadmin 的完整服務
且都建立在 minikube 的 service 均須接上你所部署的 deployment (因為helm chart把兩者包起來了)
部屬成功檔案在這
當然內部還有其他髒亂檔案
https://drive.google.com/file/d/1P98vj0DRpbPweCjaczu7Z6ub2KjafaG9/view?usp=sharing
:::
:::warning
### 方法三 修改以成功部屬的服務來完成需求
對docker-compose.yml進行修改
基礎來源是這個
https://github.com/nanoninja/docker-nginx-php-mysql
首先
`git clone https://github.com/nanoninja/docker-nginx-php-mysql.git`
`cd docker-nginx-php-mysql`
### Project tree
```
.
├── Makefile
├── README.md
├── data
│ └── db
│ ├── dumps
│ └── mysql
├── doc
├── docker-compose.yml
├── etc
│ ├── nginx
│ │ ├── default.conf
│ │ └── default.template.conf
│ ├── php
│ │ └── php.ini
│ └── ssl
└── web
├── app
│ ├── composer.json.dist
│ ├── phpunit.xml.dist
│ ├── src
│ │ └── Foo.php
│ └── test
│ ├── FooTest.php
│ └── bootstrap.php
└── public
└── index.php
```
修改以下檔案為:
```docker-compose.yml
version: '3'
services:
web:
image: nginx:alpine
container_name: nginx-41173058h
volumes:
- "./etc/nginx/default.conf:/etc/nginx/conf.d/default.conf"
- "./etc/ssl:/etc/ssl"
- "./web:/var/www/html"
- "./etc/nginx/default.template.conf:/etc/nginx/conf.d/default.template"
ports:
- "8888:80"
- "3000:443"
environment:
- NGINX_HOST=${NGINX_HOST}
command: /bin/sh -c "envsubst '$$NGINX_HOST' < /etc/nginx/conf.d/default.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
restart: always
depends_on:
- php
- mysqldb
php:
image: nanoninja/php-fpm:8.1
restart: always
volumes:
- "./etc/php/php.ini:/usr/local/etc/php/conf.d/php.ini"
- "./web:/var/www/html"
composer:
image: "composer"
volumes:
- "./web/app:/app"
command: install
myadmin:
image: phpmyadmin/phpmyadmin
container_name: phpmyadmin-41173058h
ports:
- "8080:80"
environment:
- PMA_ARBITRARY=1
- PMA_HOST=${MYSQL_HOST}
restart: always
depends_on:
- mysqldb
mysqldb:
image: mysql:${MYSQL_VERSION}
container_name: mysql-41173058h
restart: always
env_file:
- ".env"
environment:
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
ports:
- "8989:3306"
volumes:
- "./data/db/mysql:/var/lib/mysql"
```
```
cp web/app/composer.json.dist web/app/composer.json
```
```
docker-compose up -d
```
```
docker-compose logs -f # Follow log output
```
一樣使用內網穿透
使用工具為 `tailscale`
https://tailscale.com/
安裝方式
```
curl -fsSL https://tailscale.com/install.sh | sh
sudo tailscale up
```

透過內網穿透,避免麻煩的qemu端口轉發,直接對tailscale給的ip當成該機器的localhost就可以在桌機開啟網頁了。


成功開啟三個服務與網頁
:::