Dockerfile and docker-compose

9/12/2020 Taiwan Python 讀書會

10pm 開始

 

Ming-der Wang, 王銘德

(適合 Python/Docker 初學者)

 

用現成的 docker images

docker run -ti --rm -v ${HOME}:/root -v $(pwd):/git   alpine/git

或自己做一個 docker image

vi Dockerfile

docker build -t  mingder78/git   .

docker run -ti --rm -v ${HOME}:/root -v $(pwd):/git   mingder78/git

 

docker login

docker push mingder78/git 

你只有兩個方法用 docker

Dockerfile

簡單講, 用它來 dockerize (docker 化) 你的 app,

(或別人的 app)

背景知識

* docker 底層是 Linux OS

* 所以需懂 Linux 指令

* 網路的基本概念

Linux 作業系統

每一行都是

指令 + 內容 (可以用 \ 跳行)

例如:

Dockerfile 的格式

FROM python:2.7
RUN mkdir /app
WORKDIR /app
COPY main.py /app/main.py
EXPOSE 5000
CMD ["python", "main.py"]

 

FROM
RUN
WORKDIR
ADD
EXPOSE
CMD
VOLUME
ENV
COPY
LABEL
ENTRYPOINT

ONBUILD RUN

docker build

如何利用 Dockerfile 建立自己的 image (每次有改動, 就要重 build)

docker build -t mingder78/my_app:v1 .

在 Dockefile 的同一個目錄下, 執行以下 docker build 指令

當下目錄 (.)

tag 標註 (-t)

< docker id >/< app >:< tag >

(不能用大寫英文字母)

docker run

如何執行你剛出爐的 docker image

docker run -p 8080:5000 mingder78/my_app:v1

在 Dockefile 的同一個目錄下, 執行以下 docker build 指令

將 docker engine 的 8080 導到此 container 的 port 5000

用 docker images 指令可以找到你現在 docker engine 裡所有的 images

docker run -p ...

(容器可以轉 port 到不同之 docker engine 的 port)

docker engine

container (172.17.0.9)

container (172.17.0.8)

container (172.17.0.7)

container (172.17.0.6)

conatiner (172.17.0.5)

conatiner (172.17.0.4)

container (172.17.0.3)

同一台電腦裡可以裝多個 containers, 把 port 分開

IP: 192.168.1.100

6379

5000

9200

8080

8080

8081

5601

192.168.1.100:9200

192.168.1.100:5601

192.168.1.100:443

192.168.1.100:80

192.168.1.100:8080

192.168.1.100:5002

192.168.1.100:6379

docker run -p 443:8081 ...

web

瀏覽器

常用的 port numbers

知名Port即眾所周知的Port號,範圍從0到1023,這些Port號一般固定分配給一些服務。

比如:

21 Port分配給FTP服務,

                    25 Port分配給SMTP(簡單郵件傳輸協定)服務,

       80 Port分配給HTTP服務,

443 Port分配給 HTTPS 服務等等。

其他 1024 ~ 65535 port 隨便你用, 但有些已經是知名 App 常用的 port了, 例如 Flask 用 5000 

docker run -v ...

(容器可以掛載一堆本地端資料夾)

例如: docker run -it -v $PWD/rules:/usr/share/elastalert/rules ...

舉例ㄧ

用 docker 執行一個 nginx 網站, 但所有網頁資料, 並不是放在 docker images 裡, 而是要執行時, 才將網頁的內容目錄, 分享到 container 肚子裡.

 

好處是: 網頁內容可以修改, 而 docker images 不需重新 build.

舉例二

因為 docker container 刪除時, 所有 container 裡的目錄和所有檔案(資料) 全部消失.

 

所以, 如果我們開一個資料庫 container, 如何把資料庫的實體(目錄) 保持放在 container 外部目錄.

 

好處是: 資料不會消失

docker run -v 的目的

 docker run 時

如何把外部資料放入 containers 裡

* 利用 volume 概念

 

可以是 docker engine 的某些目錄

 

或是用 docker volume 產生的共用 volumes

 

* 還可以設定 container 對該目錄或檔案的權限

docker engine (volume: xxx)

container (/data)

container (/app/data.csv)

container (/xxx/test.csv)

conatiner

conatiner 

container 

./data

/test/data.csv

docker-compose

docker-compose

簡單講, 幫你執行 docker 化的app

(兩支以上相關的 apps 需要同時執行, 利用

docker-compose.yml 檔案來描述其內容)

S

docker-compose 指令

用來執行 docker-compose.yml 的內容

 

如果 docker-compose.yml 有好幾個, 可以用 -f 指定, 例如

docker-compose -f chainlink-sgx.docker-compose.yml up 

如何安裝 docker-compose

(如果無法執行 docker-compose, 再安裝)

也可以用 pip3 安裝

 

pip3 install docker-compose

docker-compose 常用指令

(一次全部 services 一起執行)

docker-compose up
docker-compose up -d       (在背後執行)
docker-compose up --build  (Dockerfile 重新 build)
docker-compose down
docker-compose down -v     (連 volume 一起刪除)
docker-compose ps          (看目前所有 services 狀態)

 

(僅用於單一 serivce)

docker-compose start
docker-compose stop
docker-compose pause
docker-compose unpause
docker-compose logs -f     (看該 service 的 logs)

開始介紹

docker-compose.yml

它是 YAML 格式

YAML 格式簡介

YAML

是"YAML Ain't a Markup Language" 

2001 年發明

強調這種語言以數據做為中心,而不是以標記語言為重點

幾乎所有語言都可以讀寫, 例如 Python 則透過 PyYAML 套件

pip install PyYAML

 

docker-compose.yml 會用到

kubernetes 也會用到

JSON

{
  "hr": 65, 
  "avg": 0.278, 
  "rbi": 147
}

YAML

hr:  65         # Home runs
avg: 0.278  # Batting average
rbi: 147      # Runs Batted In

一筆 Python dict 資料

{'avg': 0.278, 'hr': 65, 'rbi': 147}
{
  "hr": 65, 
  "avg": 0.278, 
  "rbi": 147
}

Python

Python

['Mark McGwire', 'Sammy Sosa', 'Ken Griffey']

YAML

- Mark McGwire
- Sammy Sosa
- Ken Griffey

一個字串的陣列

JSON

[
  "Mark McGwire", 
  "Sammy Sosa", 
  "Ken Griffey"
]

Python

YAML

[{'avg': 0.278, 'hr': 65, 'name': 'Mark McGwire'},
 {'avg': 0.288, 'hr': 63, 'name': 'Sammy Sosa'}]

-
  name: Mark McGwire
  hr:   65
  avg:  0.278
-
  name: Sammy Sosa
  hr:   63
  avg:  0.288

一個 dicts 的陣列

JSON

YAML

[
  {
    "hr": 65, 
    "avg": 0.278, 
    "name": "Mark McGwire"
  }, 
  {
    "hr": 63, 
    "avg": 0.288, 
    "name": "Sammy Sosa"
  }
]

-
  name: Mark McGwire
  hr:   65
  avg:  0.278
-
  name: Sammy Sosa
  hr:   63
  avg:  0.288

JSON 還是比較平易近人

YAML 獨有的

# Ranking of 1998 home runs
---
- Mark McGwire
- Sammy Sosa
- Ken Griffey

# Team ranking
---
- [name        , hr, avg  ]
- [Mark McGwire, 65, 0.278]
- [Sammy Sosa  , 63, 0.288]

* 可以有註解 (#)

* 可以多檔, 寫在一檔裡 (---)

* 兩種 array 寫法都可以, [], -

    (但 (-) 減號比較常用)

* 字串可無需用 (') 或 ('') 引號

---
id: 1
name: Ming-der Wang
scores: [99,100,36]

# Ranking of 1998 home runs
---
- Mark McGwire
- Sammy Sosa
- Ken Griffey

# Team ranking
---
- [name        , hr, avg  ]
- [Mark McGwire, 65, 0.278]
- [Sammy Sosa  , 63, 0.288]

Dockerfile

FROM python:3.7-alpine
WORKDIR /code
ENV FLASK_APP app.py
ENV FLASK_RUN_HOST 0.0.0.0
RUN apk add --no-cache gcc \ 
  musl-dev linux-headers
COPY requirements.txt \  
  requirements.txt
RUN pip install -r \ 
  requirements.txt
EXPOSE 5000
COPY . .
CMD ["flask", "run"]

docker-compose.yml

version: '3'
services:

  web:
    build: .
    command: npm run serve
    ports:
      - "5000:5000"
    volumes:
      - .:/code
    environment:
      FLASK_ENV: development
  redis:
    image: "redis:alpine"

去 docker hub, 或 container registry 找 images

docker volume 說明

version: '3'
services:

  web:
    build: .
    command: --config x
    ports:
      - "5000:5000"
    volumes:
      - dbdata:/db

volumes:

  dbdata:

volumes 不一定是目錄

可以是 docker volume

depends_on 的說明

depends_on: 會等另一個 service 起來後才開始 run,

 

所以 redis: 會先起來, 後才開始執行 web:

version: '3'
services:
  web:
    build: .
    command: --config x
    ports:
      - "5000:5000"
    volumes:
      - .:/code
    depends_on:
      - redis

  redis:
    image: "redis:alpine"

docker networks 的說明

web: service 在 frontend 網路“段" 執行

 

 

需定義 networks:

version: '3'
services:
  web:
    build: .
    ports:
      - "5000:5000"
    volumes:
      - .:/code
    networks:
      frontend:

 

networks:
  default:
    external:
      name: frontend

其他部分, 概念都跟 docker run 差不多

作業ㄧ

自己寫一個 Dockerfile 執行你自己的 Python 程式

 

(請用 git 把 Python 程式跟 Dockerfile 都放在同一目錄管理)

 

可 fork 參考 https://github.com/mingderwang/my-docker-for-python

作業二

利用 docker 開一個 jupyter 環境

(能把你的 jupyter 檔案一起放入更好)

提示: 利用 docker -v ...

Q&A

Ming-der Wang (王銘德)

Made with Slides.com