# Docker安裝與使用步驟 ver_2024.03.24 modified_2024.09.08 - LEE ## Server安裝 #### 1. 安裝Docker-Engine 在Server上先安裝Docker-Engine,照著網站步驟Install using the apt repository安裝 [[連結]](<https://docs.docker.com/engine/install/ubuntu/>) #### 2. 安裝Nvidia的套件 安裝Nvidia的套件才能在container中使用到GPU資源,照著網站的步驟,install with apt安裝即可 [[連結]](<https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html>) **<font color=red>!!!安裝完server記得要reboot!!!</font>** ``` 重啟指令二選一 sudo systemctl restart docker sudo service docker restart ``` ## 來建立並使用Docker吧 #### 1. Pull Image: 下載前人建好的Image Docker Hub中有很多前人創建的Image File,在網站搜尋下載合用的就對了。在Tag中會有不同的版本跟檔案,這次使用的nvidia/cuda的ubuntu20.04有兩種 選有devel那個12.3.1-devel-ubuntu20.04並pull下來 (titan53 我選 11.6 的版本 - 易修) >devel : Develope開發者版本,套件完整 >runtime : 執行版本,環境中套件比較簡略 [[連結]](<https://hub.docker.com/r/nvidia/cuda/tags?page=1&name=ubuntu20.4>) ``` sudo docker pull nvidia/cuda:12.3.1-devel-ubuntu20.04 ``` 查看目前有哪些已經pull下來的Image可以使用 ``` sudo docker images ``` 刪掉不要的Image ``` sudo docker rmi {ImageID} ``` #### 2. 建立Container 利用剛剛pull的Image建立container ``` sudo docker run -it -p 8888:9999 --gpus all --name {要取的名子} {ImageName:ImageTag} or sudo docker run -it -p 8888:9999 --gpus all --name {要取的名子} {ImageID} or sudo docker run -it -p 8888:9999 --shm-size="1g" --gpus all --name {要取的名子} {ImageID} ``` `-i`互動式介面 `-t` 終端介面(terminal) `-p` 設定連結的port `--shm-size` 設定share memory, 預設為64MB <font color=red>注意: 8888換成要對外連線的port,9999換成對內連線的port</font> 如果要連結host的資料夾與container的資料夾使用`-v`參數 <font color=red>注意: 硬碟內的folder記得不能重複,不然container會互相干擾</font> ``` docker run -v /host/user/data1:/mnt/data1 -it your_docker_image ``` 列出目前所有container, 確認container建立成功 ``` sudo docker ps -a ``` #### 3. 啟用剛建立的Container ``` sudo docker start {已建立的容器名子} ``` #### 4. 進入Container ``` sudo docker attach {正在執行的容器名子} ``` #### 5. 退出容器,但不關閉(會在背景執行) ``` crtl+P後ctrl+Q ``` #### 6. 這個container我不要了!! 第一步要先停止container的執行 ``` sudo docker stop {容器名子} ``` 再來移除他 ``` sudo docker rm {容器名子} ``` #### 7. 查看container們的使用情形 ``` sudo docker stats ``` # Docker的進階使用 ## Image的管理與轉移 #### 1. commit : 將建立或是修改過的容器轉換成Image 產生的新image會原封不動紀錄原本的系統,包含環境設定、硬體、檔案... <font color = 'red'>注意 : 如果有使用docker -v,掛載到硬碟上的東西不會被記錄</font> 利用`sudo docker images`可以查看新產生的Image ``` sudo docker commit {舊容器ID} {新IMAGE名稱}:{IMAGE_TAG} ``` #### 2. save : 將Image檔案匯出成tar方便使用隨身碟轉換 ``` sudo docker save -o {取名子}.tar {ImageName:Tag} ``` #### 3. load : 複製到指定裝置後如何安裝Image.tar檔 ``` sudo docker load -i {ImageName}.tar ``` ## DockerFile與Entrypoint 簡單來說,DockerFile是指定Container建立過程的指令檔 可以將額外功能或指令包裝進Image中 #### 1. 首先要先準備好Dockerfile,基本範例如下 !!!注意,Dockerfile檔名必須為Dockerfile!!! ``` FROM ubuntu:20.04 RUN apt-get update && apt-get upgrade ``` > `FROM`代表要使用的image,`RUN`讓我們在建立的container中執行的shell指令 #### 2. 接著用這個Dockerfile建立image吧 ``` sudo docker build -t {產生的Image名稱} . ``` > `-t`代表target後面加上image的名稱,`.`是Dockerfile所在位置 #### 3. 成功建立Image 成功建立image可以使用`sudo docker images`查看,並使用`sudo docker run`建立容器 #### 4. 那什麼是Entrypoint呢...... 只有Dockerfile是不夠的,如果想客製化每個容器,可以透過使用`ENTRYPOINT`指定創建容器時執行特定bash檔,並且利用`-e`傳入環境變數提供bash檔使用 ``` FROM nvidia-11.4.3-ssh:latest COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] ``` 創建容器時傳入bash檔`entrypoint.sh`對應的環境變數 ``` docker run -it --name {容器名} -e {環境變數名}={想傳入變數} {ImageID} ``` # 常見問題 ## 從 Putty 連進 Container 的前置作業 #### 1. 在 container 裡面裝好 vim 以及 ssh ``` apt install vim -y apt install openssh-server -y ``` > `-y`不用在`yes/no`時輸入 => 直接`yes` #### 2. 於 container 內更改參數 ``` vim /etc/ssh/sshd_config ``` 文件內更改 3 項後存檔: ``` 取消註解 PORT XX PermitRootLogin yes PasswordAuthentication yes ``` #### 3. 設置密碼 ``` passwd ``` #### 4. 將 ssh 重啟 ``` /etc/init.d/ssh restart ``` <font color = 'red'> 完成! </font> ## 在連線時的環境變數問題 舉個栗子🌰, 你要使用pytorch, 開開心心的pull一個官方image下來, 然後建立好container, 接著你在裡面安裝了ssh, 然後在外部透過putty連進來後發現, 無法執行python, ``` python hello.py # -bash: command not found: python. ``` 這時候你就懷疑自我了, 剛剛我用docker attach {container_id}進去之後, 明明可以順利執行阿? 這邊要提到的是, 用putty連線linux時, 系統會預設去執行/etc/profile, 所以你要做的事情是把python的位置加入。 在使用attach進入container的本地端可以利用下面指令取得python路徑 ``` which python ``` 首先, 把python的位置加入環境變數, ``` export PATH={/opt/conda/lib/}:$PATH // {裡面放python的路徑} ``` 然後, 在一個地方創建env.txt, 把環境變數存入 ``` env > env.txt ``` 接著,把所有在env.txt裡面的字, 複製到/etc/profile裡面(注藥要保留原本的內容, 貼在後面就好) 最後, source它 ``` source /etc/profile ``` 之後你用putty連進container也可以找到正確的python了! 另解如下 ``` 1. 在本地端找到python路徑 which python 2. 在~/.bashrc最後加入連結路徑 export PATH={/opt/conda/lib/}:$PATH 3. 啟動bashrc source ~/.bashrc ``` > ./bashrc是一個在用戶登入時會執行的設定檔,因此我們將python執行路徑加入就會在登入同時重新連結 > 不能運作的原因,有可能是透過遠端連線使用root登入時,會執行的設定檔為`/root/.profile`,若檔案不存在可以自行建立,內容為`source ~/.bashrc`,就能正常呼叫.bashrc設定檔了 ## container無法聯網 - container中無法順利聯網,連`apt update`都不行 >> 重啟docker服務 ``` sudo systemctl restart docker ``` ## 其他 #### 學習資源 [[開源電子書 Docker--從入門到實踐]](<https://philipzheng.gitbook.io/docker_practice/>) #### 筆記: 創立平行計算docker指令 ``` sudo docker run -it -p 8888:22 -e USERNAME=test123 --gpus all --name test123 my-ubuntu:latest ``` > `docker run`的時候,`--rm` 退出將會自動刪除容器,對於測試階段相當好用 #### 紀錄使用過的Image hub - cnstark/pytorch映像檔不錯可以直接使用torch和GPU ``` sudo docker pull cnstark/pytorch:2.0.0-py3.9.12-cuda11.8.0-devel-ubuntu22.04 ``` #### commit vs. build 傻傻分不清楚 - commit : 從container創建Image - build : 透過Dockerfile為Image添加資訊後建立新的Image > GPT: 簡而言之,Dockerfile中的指令主要用於建立image,而不是在每次attach container時執行。 若要在container運行時執行特定命令,可以使用docker exec。 <!-- ### 未整理與待解決 ... -->