--- tags: LSA --- [toc] # Docker 筆記版 ## 虛擬機器 vs 容器 ### 虛擬機器(以作業系統為中心) ![VM](https://oer.gitlab.io/oer-on-oer-infrastructure/figures/OS/virtual-machines.png) :::info 透過選擇不同的 Guest OS,虛擬機器的技術就可以確保只要我的程式在該 Guest OS 上可以正常運作,那放到你的電腦上跑時,可以不管你的 Host OS 是什麼,只要在你的 Host OS 上先裝上我的 Guest OS,我的程式就可以正常在你的電腦上運作。 ::: ### 容器(以應用程式為中心) ![container](https://oer.gitlab.io/oer-on-oer-infrastructure/figures/OS/containers.png) :::info 容器是在作業系統層上虛擬化,透過 Container Manager 直接將一個應用程式所需的程式碼、函式庫打包,建立資源控管機制隔離各個容器,並分配 Host OS 上的系統資源。透過容器,應用程式不需要再另外安裝作業系統(Guest OS)也可以執行。 因為不需要另外安裝作業系統,建立容器所需要的硬碟容量可以大幅降低,且啟動速度可以更快,不需要等待 Guest OS 的開機時間。 ::: ## Container manager (底層實做) - rkt (appc) - **docker** (runc) - LXC/LXD ## 管理工具 - docker compose - docker swarm (stack) - k8s ## 為什麼要用 Container ### 更輕鬆的遷移和擴展 (why not baremetal) ||baremetal|container| |-|---------|---------| |遷移|人工處理|指令一鍵處理| |擴展|再來一台|指令一鍵處理| ### 更簡單的管理 (why not baremetal) |baremetal|container| |---------|---------| |無內建 |指令一鍵處理| ### 更快速的交付和部署 (wht not vm) - container只需要將你的code的部屬即可 - container不需管理跟你服務無關的東西(軟體) - container不需關心相依性 ### 更有效率的虛擬化 (why not vm) - container 只須將你的 process 、 network 虛擬化 - 其他東西與host共用 ### 對比傳統虛擬機總結 |特性|容器|虛擬機| |-|-|-| |啟動|秒級|分鐘級| |硬碟容量|一般為 MB|一般為 GB| |效能|接近原生|比較慢| |系統支援量|單機支援上千個容器|一般幾十個| ## 各種container - 其都具備 - 容器標準化 - 具有可攜式性 - 高效地利用伺服器 - 透過namespace and cgroup 來分配不同軟體容器的可用硬體資源 ### LXC/LXD - Linux Containers的縮寫 - 內含服務本身的程式碼,以及所需要的作業系統核心和函式庫 - 使用上可取代 VM 部分功能,但是更輕量 - [try it](https://linuxcontainers.org/lxd/try-it/) ### docker - 通常只內含服務本身的程式碼 - 通常為一次性使用 - 免洗 container ### rkt - 跟 docker 差不多 - 因應 docker 背離 CoreOS 創辦人初衷而研發 - EOL - [official doc](https://coreos.com/rkt/docs/latest/rkt-vs-other-projects.html) ### kata container ![](https://katacontainers.io/static/6e497f9d3752ca1e354d0d2949abc020/8fef6/katacontainers_traditionalvskata_diagram.jpg) ## Why choose docker - docker 比較多人用 - 知名度高 - 社群支援度高 ## 實現方式與演進 - Docker一開始就是dotCloud的內部專屬專案, - Docker的開發者是: - Solomon Hykes - Andrea Luzzardi - Francois-Xavier Bourlet - Jeff Lindsay - 專案如果只用在公司內部,實在是太可惜了 - Docker成為Open Source的專案 - 透過namespace and cgroup 來分配不同軟體容器的可用硬體資源 - 0.9版前其使用lxc,之後是使用runc - 0.9版前是基於很多東西造就docker,既然來如此自己寫一個 - 支援windows ## Docker 3 + 1 元素 ### 映像檔 Image - 一個映像檔裡只包含運行該服務所需的檔案 - 建造方式: - 利用 dockerfile 建造 - 儲存執行中 container 狀態 ### 容器 Container - 用映像檔建立出來後執行 - 可以被啟動、開始、停止、刪除 - 每個容器都是相互隔離、相對安全的平台 - 包含該映像檔加上一層讀寫層 - 映像檔為唯牘 ### 倉庫 Repository - 集中存放映像檔檔案 - 倉庫註冊伺服器 (Registry) - 存放著多個倉庫 - 最大的公開倉庫註冊伺服器是 Docker Hub ### Volume - 永久存放資料的地方 ## 生命週期 ![](https://image.slidesharecdn.com/docker-architecture-v2-140906002548-phpapp02/95/docker-architecture-v13-15-638.jpg?cb=1415102222) - 資料會於 killed 時刪除 - 資料長期儲存要掛 volume ## namespace - 隔離 Process ID 命名空間 - 不同 PID 命名空間 可以擁有相同的 PID - PID 命名空間 容許 containers 提供: - 暫停 / 恢復 container 中的一組 processes - 將 container 遷移到新主機,container 的 process 保持相同的 PID - [Linux Programmer's Manual](http://man7.org/linux/man-pages/man7/pid_namespaces.7.html#top_of_page) ## Network Mode - bridge (預設使用的 mode) - Docker 會分配一個內網 ip 給 container - overlay - 不同的實體主機內的 Container 之間可以互相的溝通 - macvlan - 允許你在主機的一個網路卡上配置多個虛擬的網路卡 - container 的網路和Host 都在同一個網段中 - none - container 沒有網路 ## docker install - [docker install docs](https://docs.docker.com/engine/install/ubuntu/) - install ```shell= sudo apt-get remove docker docker-engine docker.io containerd runc 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 sudo apt-get install docker-ce docker-ce-cli containerd.io ``` - Verify that Docker Engine is installed correctly `sudo docker run hello-world` ## 操作映像檔 ### 一般操作 - 取得映像檔 `docker pull ubuntu:18.04` - 列出映像檔 `docker images` - 刪除 image `docker rmi lsa/nginx` ![](https://i.imgur.com/CB3ef20.png) :::info 如果沒有指定 `TAG`,預設使用 `latest` - repository: 來自於哪個倉庫,比如 ubuntu - tag: 映像檔的標記,比如 14.04 - image id: 它的 ID 號(唯一) - create: 建立時間 - size: 映像檔大小 ::: ### 建立映像檔 #### 儲存執行中 container 狀態 ```shell= sudo docker run -it ubuntu:18.04 /bin/bash touch a exit sudo docker commit -m "add file" <container name> lsa/ubuntu sudo docker run -it lsa/ubuntu /bin/bash ``` #### 利用 dockerfile 建造 - 使用 docker commit 擴展一個映像檔比較簡單,但是不方便在一個團隊中分享 - 使用 docker build 來建立一個新的映像檔 - 需要建立一個 Dockerfile,裡面包含一些用來建立映像檔的指令 ```shell= curl https://raw.githubusercontent.com/HcwXd/docker-tutorial/master/docker-demo-app/docker.html > index.html vim Dockerfile ``` ```dockerfile= FROM nginx:latest ADD index.html /usr/share/nginx/html ``` - 使用#來註釋 - `FROM` 指令告訴 Docker 使用哪個映像檔作為基底 - `RUN` 開頭的指令會在建立中執行,比如安裝一個套件 - `ADD` 命令複製本地檔案到映像檔 - `EXPOSE` 命令向外部開放埠號 - `CMD` 描述容器啟動後自動呼叫的程序 ```shell= docker build -t="lsa/nginx" . docker run -p 8000:80 -d --name lsa lsa/nginx ``` `用瀏覽器打開主機的IP加:8000`[範例](http://localhost:8000) - -t 標記添加 tag - 注意一個映像檔不能超過 127 層 #### 存出和載入 - 想讓對方知道你做了什麼 ```shell= docker save -o <name>.tar <image name> docker load -i <name>.tar ``` - 單純deploy(歷史會不見) ```shell= docker export -o <name>.tar <container name> docker import <name>.tar ``` - layer image hash會對應不到(save and load)`docker image history` 原本的: ```shell= IMAGE CREATED CREATED BY SIZE COMMENT ca4502c36302 10 seconds ago /bin/sh -c #(nop) ADD file:a0c534257e73fab40… 7.48kB ed21b7a8aee9 2 weeks ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… 0B <missing> 2 weeks ago /bin/sh -c #(nop) STOPSIGNAL SIGTERM 0B <missing> 2 weeks ago /bin/sh -c #(nop) EXPOSE 80 0B ... ``` load後: ```shell= IMAGE CREATED CREATED BY SIZE COMMENT ca4502c36302 5 minutes ago /bin/sh -c #(nop) ADD file:a0c534257e73fab40… 7.48kB <missing> 2 weeks ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon… 0B <missing> 2 weeks ago /bin/sh -c #(nop) STOPSIGNAL SIGTERM 0B ... ``` - export and import`docker image history` import後: ```shell= IMAGE CREATED CREATED BY SIZE COMMENT 7d6e3f6dc970 39 seconds ago 125MB Imported from - ``` ## 操作容器 ### 一般操作 - 建立容器 `docker run -it --name myubuntu -P 8000:22 ubuntu bash` - 終止 `docker stop myubuntu` - 啟動容器 `docker start -it myubuntu bash` - 重新啟動 `docker restart myubuntu` - 查看容器訊息 `docker ps -a` #### behind the scenes - 檢查本地是否存在指定的映像檔,不存在就從公有倉庫下載 - 利用映像檔建立並啟動一個容器 - **分配一個檔案系統,並在唯讀的映像檔層外面掛載一層可讀寫層** - 從宿主主機設定的網路橋界面中橋接一個虛擬埠到容器中去 - 從位址池中設定一個 ip 位址給容器 - 執行使用者指定的應用程式 - 執行完畢後容器被終止 ### 進入容器 - exec 命令 `docker exec [OPTIONS] CONTAINER` - attach 命令 `docker attach [OPTIONS] CONTAINER` - 按下 `ctrl` + `P` 然後 `ctrl` + `Q` 跳離容器,讓它繼續在背景執行。 :::warning 但是使用 attach 命令有時候並不方便。當多個窗口同時 attach 到同一個容器的時候,所有窗口都會同步顯示。當某個窗口因命令阻塞時,其他窗口也無法執行操作了。 ::: #### lab :::danger 這是為了lab測試用,平常不建議用 -itd ::: - start container `sudo docker run -idt --name lsa ubuntu` - exec `sudo docker exec -it lsa bash` - attach `sudo docker attach lsa` ## 倉庫 (Repository) - 指令查詢 `docker search [OPTIONS] TERM` - 網頁查詢 [docker hub](https://hub.docker.com) ## 資料卷 (Volume) - 資料長時間保存 - 資料卷可以在容器之間共享和重用 - 對資料卷的修改會立馬生效 - 對資料卷的更新,不會影響映像檔 :::info 資料卷的使用,類似於 Linux 下對目錄或檔案進行 mount。 ::: - 使用自建 volume ```shell= docker volume create --name <name> docker volume ls docker run -d --name web -v <name>:/webapp nginx ``` - 使用系統目錄 ```shell= docker run -d --name web -v ./log:/var/log/nginx nginx ``` ## 網路連線 - 使用 ip 直接連接 - 利用`docker inspect`來取得ip - 外部存取容器 - `-p ip:hostPort:containerPort` - 容器互聯 `--link name` - `name` 是要連接的容器名稱 ```shell= sudo docker run -d --name web --link db -p 8000:80 nginx ``` ## docker compose ```yaml= version: '3' services: db: container_name: postgres image: postgres # build: ./postgres restart: always # 自動重新使用 environment: <name>: <value> volumes: ... # depends_on: # - <some container> volumes: # 有使用到的 # networks: # default: # external: # join a pre-existing network, # name: im-pub ``` ### install ```shell= udo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose sudo chmod +x /usr/local/bin/docker-compose ``` https://github.com/yiyu0x/ncnu-course-api https://github.com/vincentinttsh/docker-compose-test ## Docker swarm ### Why need it - Scaling - 自動修復 - 當 container 的 host 死後,自動於其他台重啟 - Load balancing - Rolling updates ### 優缺點( V.S. k8s ) - 優點( - 完備的相關技術文檔 - 快速簡單的配置 - 缺點 - 不提供存儲選項 - 監控不良 - Docker Swarm只提供關於容器的基本信息 ### How - Cluster 主要由 Master Node 與 Worker Node 兩種角色所組成 - Manager Node 負責管理 Node Worker 與協調 Container 的部署工作 - 可以由一群 Manager Node 所組成 Manager Cluster(應付單點失效) - 由單數數量的 Node 節點來組成。 - 透過一種去中心化的 [Raft 驗算法](http://thesecretlivesofdata.com/raft/) - Worker Node - 責執行 Container - 透過 Stack Network建立虛擬網路,並且透過加密的方式進行連線。 ![](https://blog.toright.com/wp-content/uploads/2017/10/swarm-diagram-1-640x300.png) ### Use it - 修改docker-compose.yml - 增加設定 `deploy` - [doc](https://docs.docker.com/compose/compose-file/#deploy) ## 參考資料 [Docker 基礎教學與介紹 ](https://medium.com/unorthodox-paranoid/docker-tutorial-101-c3808b899ac6) [Docker —— 從入門到實踐](https://philipzheng.gitbook.io/docker_practice/) [CoreOS 实战:CoreOS 及管理工具介绍](https://www.infoq.cn/article/what-is-coreos/)