# 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 的輸出畫面(右上) ![Termius - ws2.csie.ntu.edu.tw 2024_3_28 上午 02_29_34](https://hackmd.io/_uploads/BkfA_VEkA.png) VM 內開機完成的畫面 ![VM-HW05 (QEMU (41173058h)) - RealVNC Viewer 2024_3_29 下午 08_36_31](https://hackmd.io/_uploads/HkG7IEVkC.png) VM 內登入後的畫面 ![VM-HW05 (QEMU (41173058h)) - RealVNC Viewer 2024_3_29 下午 08_37_05](https://hackmd.io/_uploads/HkLFUNVk0.png) VM 內執行 ip a 指令的輸出畫面 ![VM-HW05 (QEMU (41173058h)) - RealVNC Viewer 2024_3_29 下午 08_39_53](https://hackmd.io/_uploads/Bkvs8VVkA.png) 失敗時刪除用指令 ``` 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 ![Termius - ws2.csie.ntu.edu.tw 2024_3_28 上午 02_29_34](https://hackmd.io/_uploads/SJpkhVNyA.png) ### 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 ``` ![Termius - NASA-hw5-VM 2024_3_29 下午 09_04_26](https://hackmd.io/_uploads/SkqDhNNJA.png) ![Termius - NASA-hw5-VM 2024_3_29 下午 09_05_50](https://hackmd.io/_uploads/rkRh2E4yR.png) <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 (左下) ![Termius - NASA-hw5-VM 2024_3_29 下午 08_43_40](https://hackmd.io/_uploads/BJI5PEV1R.png) <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 ``` ### 截圖 成功的截圖(左上) ![Termius - ws2.csie.ntu.edu.tw (1) 2024_3_28 下午 08_13_35](https://hackmd.io/_uploads/ByK5FN4yR.png) ![image](https://hackmd.io/_uploads/BJRC6SEkR.png) :::warning 這邊我使用了一個比較外掛的手段,內網穿透 使用工具為 `tailscale` https://tailscale.com/ 安裝方式 ``` curl -fsSL https://tailscale.com/install.sh | sh sudo tailscale up ``` ![image](https://hackmd.io/_uploads/H1GuWrNyA.png) 透過內網穿透,避免麻煩的qemu端口轉發,直接對tailscale給的ip當成該機器的localhost就可以在桌機開啟網頁了。 ::: <div style="page-break-after:always;"></div> ## 8 以下指令即可進入 ``` docker exec -it nginx-1 /bin/bash ``` (左上) ![image](https://hackmd.io/_uploads/BytfArVJ0.png) ## 9 以下指令即可查看 ``` docker exec nginx-1 cat /etc/nginx/nginx.conf ``` (左上) ![image](https://hackmd.io/_uploads/HylSCSEJR.png) <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 ``` ![Termius - nasa-hw5-VM 2024_3_28 下午 10_51_38](https://hackmd.io/_uploads/BJsLqE4JR.png) <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 ``` ![image](https://hackmd.io/_uploads/H1GuWrNyA.png) 透過內網穿透,避免麻煩的qemu端口轉發,直接對tailscale給的ip當成該機器的localhost就可以在桌機開啟網頁了。 ::: ![image](https://hackmd.io/_uploads/Hyz99E4yR.png) ![image](https://hackmd.io/_uploads/HyDc9NNyA.png) <div style="page-break-after:always;"></div> ## 15 ![image](https://hackmd.io/_uploads/SJJlxrEy0.png) 以下是 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 ``` ![image](https://hackmd.io/_uploads/H1GuWrNyA.png) 透過內網穿透,避免麻煩的qemu端口轉發,直接對tailscale給的ip當成該機器的localhost就可以在桌機開啟網頁了。 ![image](https://hackmd.io/_uploads/HJ5jqN4y0.png) ![image](https://hackmd.io/_uploads/H1x25ENJ0.png) 成功開啟三個服務與網頁 :::