Docker

技術筆記

參考資料

安裝

Ubuntu

sudo apt-get install apt-transport-https ca-certificates curl software-properties-common
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

CentOS

sudo yum install -y yum-utils device-mapper-persistent-data lvm2
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce

單位

  • 映像檔(image)
    • 類似 docker 的模板
    • image 類似模板,要用 image 開出來的 container 才能用
    • 名詞
      • NAME
      • DESCRIPTION: 描述
      • AUTOMATED
      • REPOSITORY (倉庫)
      • TAG: 標記,通常會存版本號
      • IMAGE ID: image 被抓下來時,隨機產生的唯一 ID
  • Dockerfile
    • 將 docker 與相關安裝執行指令寫成操作檔案
  • 容器(container)
    • 建立出來的執行實力
    • 基本上是基於 image 在跑得 => 開出 container 後不能將 image 刪掉,or 可能會跑不動
    • 可以用 image 創
    • 可以用 Dockerfile 創
    • 可以被啟動、開始、停止、刪除
  • 倉庫(Registry)

指令

Hub

  • docker search [image]
    • 從 Docker Hub 上搜尋是否有相關名字的 docker image
  • docker pull [image]
    • 將 docker image 從 Docker Hub 上下載下來
  • docker login
    • 登入 Docker Hub
  • docker push [image]
    • 把 docker image 推上 Docker Hub
    • 基本上倉儲相關指令與 Git 相同
    • 注意:docker push 必須有 namespace,也就是當初對 images 命名時,要記的命成 username/imagename

Image

  • docker images
    • 將所有的 docker image 列出
  • docker run [image]
    • 啟動一個 container
    • 通常後面會接一個操作指令,操作完就結束 container
      • e.g. docker run Ubuntu /bin/echo "Hello World"
    • -i: 標準輸入保持打開
    • -t: 讓Docker分配一個虛擬終端(pseudo-tty)並綁定到容器的標準輸入上
    • 通常 -i -t 會合用
      • e.g. docker run -t -i Ubuntu /bin/bash
    • -d: 進入背景執行
  • docker rmi [image]
    • 刪除 image
  • docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]
    • OPTIONS
      • --author, -a: 作者
      • --message, -m: commit message
    • container
      • 要 commit 的 container => commit 完後便會變成新的 image
    • REPOSITORY
      • 如果想要對產出的 image 做命名
  • docker load/save IMAGE
    • 匯入 or 匯出(儲存) image (像是存成 .tar)
  • docker build [Dockerfile]
    • 從 Dockerfile 編譯

Container

  • docker ps
    • 列出目前在執行的 container
    • -a: 列出全部的 container(包含關機的)
  • docker start [CONTAINER ID / CONTAINER NAME]
    • 啟動關機的 container
  • docker stop [CONTAINER ID / CONTAINER NAME]
    • container 關機
    • 關機後會留下殘骸 => 可以再次開啟
  • docker restart [CONTAINER ID / CONTAINER NAME]
    • 重新開機
  • docker logs [CONTAINER ID / CONTAINER NAME]
    • 列出這個 container 曾經的 stander output
  • docker exec [CONTAINER ID / CONTAINER NAME]
    • 將在背景執行的 container 提出來
    • 通常配合 -i -t,回到互動視窗
  • docker rm [CONTAINER ID / CONTAINER NAME]
    • 刪除 conatiner
  • docker import / export CONTAINER
    • 匯入 or 匯出 container
    • -o NAME.tar: 指定匯出格式 (ex .tar)

Data Volumes

分別有 Data Volumes 與 Data Valume Container 兩種

  • Data Valumes
    • 將主機目錄對應到容器中,類似 mount
    • docker run -v {容器內資料夾} IMAGE: 會在主機內建一個資料夾掛載上去
    • docker run -v {主機內資料夾}:{容器內資料夾} IMAGE: 直接用已存在的資料夾掛載
    • 可以多個容器掛載到同一個主機資料夾
    • 多個 -v 參數可以掛載多個資料夾
    • 容器內資料夾一定要是絕對路徑,主機則不一定
    • 預設為 rw,可用 docker run -v {主機內資料夾}:{容器內資料夾}:ro IMAGE 改成唯讀
  • Data Valume Container

Attach Device

  • USB:
    • docker run --device=/dev/ttyUSB0 -it ubuntu /bin/bash
  • NVIDIA GPU:
    • docker run --device=/dev/nvidia0 -it ubuntu /bin/bash

RESTful API

修改 /etc/docker/daemon.json

{
  "live-restore": true,
  "group": "dockerroot",
  "insecure-registries": ["0.0.0.0:5000"],
  "hosts": [
     "unix:///var/run/docker.sock",
     "tcp://0.0.0.0:2375"
  ]
}

jupyter/tensorflow-notebook 為例,開啟 RESTful api 後,docker CLI 指令要用 Root 執行

sudo docker pull jupyter/tensorflow-notebook

修改完後,重啟 docker service: sudo systemctl restart docker

操作

  • docker version:
curl -X GET http://localhost:2375/version
  • docker pull jupyter/tensorflow-notebook:
curl -X POST http://localhost:2375/images/create?fromImage=jupyter/tensorflow-notebook
  • docker images:
curl -X GET http://localhost:2375/images/json
  • docker create -p 8080:80 jupyter/tensorflow-notebook:
curl -H "Content-Type: application/json" http://0.0.0.0:2375/containers/create?name=tensor -d '{
    "Image": "jupyter/tensorflow-notebook",
    "HostConfig":{
        "Memory": 4194304,
        "NanoCPUs": 2000000000,
        "PortBindings": {
            "80/tcp": [{"HostPort": "8080"}]
        },
        "Dns": ["8.8.8.8"],
        "Devices": [{
            "PathOnHost": "/dev/nvidia0",
            "PathInContainer": "/dev/nvidia0",
            "CgroupPermissions": "rwm"
        }]
    }
}'
  • docker ps -a:
curl -X GET http://localhost:2375/containers/json?all=true
  • docker start tensor:
curl -X POST http://localhost:2375/containers/tensor/start
  • docker stop tensor:
curl -X POST http://localhost:2375/containers/tensor/stop
  • docker rm tensor:
curl -X DELETE http://localhost:2375/containers/tensor?v=true

參考 Docker security

Nvidia-docker

參考 nvidia-docker

  • 有 cuda 但沒有 cudnn
  • 魔改
    • 下載 cudnn: https://docs.nvidia.com/deeplearning/sdk/cudnn-install/index.html
    • 解安裝到 jupyter/driver (之後會一起 mount 進 container):
      tar -xzvf cudnn-9.0-linux-x64-v7.tgz
      
    • 開啟一個 container volumn
      docker volumn create cudnn
      
    • 把 container volumn 與 jupyter folder 同時 mount 入 container
      docker run --runtime=nvidia -v /home/intern2018/NCHC-docker-test/jupyter:/jupyter -v cudnn:/cudnn -it calee0219/jupyter-docker
      
    • 照 doc 安裝 cudnn (複製貼上、修改權限):
      cp /jupyter/driver/cuda/include/cudnn.h /usr/local/cuda/include
      cp /jupyter/driver/cuda/lib64/libcudnn* /usr/local/cuda/lib64
      chmod a+r /usr/local/cuda/include/cudnn.h /usr/local/cuda/lib64/libcudnn*
      
    • 測試
      • 改環境變數指向
        export LD_LIBRARY_PATH=/usr/local/cuda/lib64:$LD_LIBRARY_PATH
        
      • 測試 script
        import sys
        import numpy as np
        import tensorflow as tf
        from datetime import datetime
        
        device_name = sys.argv[1]  # Choose device from cmd line. Options: gpu or cpu
        shape = (int(sys.argv[2]), int(sys.argv[2]))
        if device_name == "gpu":
            device_name = "/gpu:0"
        else:
            device_name = "/cpu:0"
        
        with tf.device(device_name):
            random_matrix = tf.random_uniform(shape=shape, minval=0, maxval=1)
            dot_operation = tf.matmul(random_matrix, tf.transpose(random_matrix))
            sum_operation = tf.reduce_sum(dot_operation)
        
        startTime = datetime.now()
        with tf.Session(config=tf.ConfigProto(log_device_placement=True)) as session:
                result = session.run(sum_operation)
                print(result)
        
        # It can be hard to see the results on the terminal with lots of output -- add some newlines to improve readability.
        print("\n" * 5)
        print("Shape:", shape, "Device:", device_name)
        print("Time taken:", str(datetime.now() - startTime))
        
    • /usr/local/cuda/ 全部丟入 container volumn 內
      cp /usr/local/cuda/* /cudnn
      
    • 之後都把 container volumn mount 到 /usr/local/cuda/
      docker run --runtime=nvidia -v /home/intern2018/NCHC-docker-test/jupyter:/jupyter -v cudnn:/usr/local/cuda/ -it calee0219/jupyter-docker
      

Dockerfile


GPU

--divice=/dev/nvidia0

comments powered by Disqus

Related