Skip to content

docker

淺談 Moby’s BuildKit

  • Dev, Ops

前陣子因為工作需要,研究了一下所謂 Docker build 的 3.0 版本 —— docker buildx build,希望能找出其與 docker build 背後的差異

docker buildx 指令是使用 Moby’s BuildKit 這套工具來代理 building,所以以下會用 BuildKit 來指稱新的建構模式

直接下結論

  • BuildKit 須要透過一個前端服務去轉換 Dockerfile (或其他語言定義的建構流程),再交給 LLB 處理
  • 即使是同一個 Dockerfile,docker build/buildx 兩者建構出的 layer 完全不同,無法共享
  • 如果你建構很複雜,已經有在使用 multi-stage build(例如須要先編譯成二進制檔案),那會比較有幫助,如果是要 build 類似 python 這種直譯式的應用程式,因為流程較為單純所以幫助不大

Read More »淺談 Moby’s BuildKit

HBase Basics

  • Ops

Apache HBase is an open source, scalable, consistent, low latency, random access data store

Source from Infinite Skills

Features

Horizontally Scalable

Linear increase in servers results in linear increases in storage capacity and I/O operations

image

CAP Trade off

In CAP theory, Hbase is more likely a CP type of system

  • Consistency: ACID(atomicity, consistency, isolation, durability) garantees on rows
  • Availability: Response time 2-3ms from cache, 10-20ms from disk
  • Partition Tolerance: Failures don’t block system. It might take longer to response to maintain consistency

Dependencies

Apache ZooKeeper

  • Use for distributed coordination of leaders for high availability
  • Optimized to be highly avaiable for reads
  • Not designed to scale for high write throughput

Apache Hadoop HDFS

  • Provide data durability and reliability
  • Optimized for sequential reads and writes of large files
  • Does not provide random updates, only simple API for rando reads
  • Cannot scale tens of billions of small entities (less then a few hundred MB)

Both system have their strengths but do not individually provide the same properties as HBase

Random Access

Optimized for small random reads

  • Entities indexed for efficient random reads

Optimized for high throughput random writes

  • Updates without requiring read
  • Random writes via Log Structured Merge (LSM)

Short History

Inspired from Google’s Bigtable

Bigtable: A Distributed Storage System for Structured Data(2006)

BigTable

Datastore for Google’s Web Crawl Table

  • Store web page content
  • Web URL as key
  • Use MapReduce to find links and generate backlinks
  • Calculate page rank to build the Google index

Later, it also used as backend for Gmail, GA, Google Earth etc.

Hadoop HDFS

Inspired by Google distributed file system GFS

Timeline

Since 2009, many compaies (Yahoo, Facebook, eBay etc.) chose to use HBase for large scale production use case

In 2015, Google announced BigTable with HBase 1.0 compatible API support for its compute engine users

2017, HBase 2.0.0

2020, HBase 3.0.0

Despite being bucketed into NoSQL category of data storage, some of intresting are moving NoSQL back to SQL, by using HBase as a storage engine for SQL compliant OLTP database system.

Use case

HBase’s strengths are its ability to scale and sustain high write throughputs

Many HBase apps are:

  • Ports from RDBMS to HBase
  • New low-latency big data apps

How to Porting RDBMS to HBase?

  • Many RDBMS are painful to scale
  • Scale up is no longer pratical for massive data
  • Data inconsistency was not acceptable when scaling reads
  • Operationally gets more complicated as the number of replicas increases
  • Operational techniques not sufficient when scaling writes

To make it easier to scale, we need to discard the fundamental features that RDBMS provides, such as:

  • text search (LIKE)
  • joins
  • foreign keys and avoid constraint checks

Changing the schema, make it only contains denormalized tables, we won’t incur replication IO when sharding the RDBMS

Now you’re relatively straightforward porting RDBMS to HBase

Why choosing HBase instead?

  • When your apps need high wirte and read throughput
  • When you tired of RDMS’s fragile scaling operations

Data Volumes

  • Entity data: information about the current state of a particular persion or thing
  • Event data(or time series data): Records events that are generally spaced over many time intervals

Data volume explods when we need both of them

HBase or Not

Q: Does your app expect new data to be vailable immediately after an update?

  • Yes: Use HBase
    • When data queried, must reflect the most recent values
    • Expect query responses in milliseconds
  • No: No need for HBase

Q: Whether your app analytical or operational?

  • Analytical: Not optimal for HBase
    • Look for large set of data
    • Often filter for particular time range
    • Better choose Hadoop
  • Operational: Use HBase
    • Look for single or small set of entities

Q: Does your app expect updates to be available immediately after an update?

  • Yes: Use HBase
    • Frequently modified
    • Pinpoint deletes
    • Updates must be reflected within milliseconds
  • No: No need for HBase
    • Data is append-only
    • Deletes in bulk or never
    • Updates can be ignored until the next report is run

comparison

Workload HBase Hadoop
Low Latency 1ms from cache 10ms from disk 1min vis MR/Spark 1s via Impala
Random Read Rowkey is primary index The small file problem
Short Scan Sorted and efficient Bespoke partitioning can help
Full Scan Possible but non-optimal Improved pref w/MR on snapshots Optimized with MR, Hive, Impala
Updates Optimized Not supported

Read More »HBase Basics

Docker Swarm 進階實戰 (2)

  • Ops
tags: docker, devops

Docker Swarm進階實戰(2)

Service Logs

  • 是container logs的聚集
  • 可以印出全部tasks或單一task
  • 如果你沒有log system,這可能是唯一troubleshooting的方式
  • 沒有storage,、不支援log搜尋或轉送至其他系統
  • 如果你有設定--log-driver,也就是其他logging方式,此指令就抓不到任何logs

除非你是小型swarm或測試階段,才使用一般的service logs,長期還是需要其他log storage的解決方案

範例指令

印出時不被截斷

只取最近50筆

Linux跟Mac可以透過grep做簡單的篩選

Windows透過findstr

Docker Events

  • Docker engine或Swarm產生的操作(Action)紀錄
  • 紀錄service/node/secret/config/network等的新增修改刪除動作
  • 支援搜尋及formatting
  • 分兩種scope,分別是swarm level跟local level(單一node)
  • event存在實體記憶體,最多只能存1000筆,所以當node數量很多時,event就不堪用了,還是需要額外的logging system

範例指令 顯示local events,如果node是manager,會顯示swarm events

--since

--filter

Swarm Configs

可以在Swarm的Raft Database儲存字串或檔案,並mapping容器中,適合的應用場景為:

  • nginx設定或更改proxy config
  • 設定或更改資料庫config等 這樣可以取代bind mount(將資料儲存在硬碟),存在Raft能提高可用性 swarm config跟secret有異曲同工之妙,可以透過指令來新增刪除config files,要注意的是:
  • config是immutable,不能修改只能replace
  • 若有任何service使用到該config,要先移除service才能移除config
  • 如果是隱私資料一樣用secret來存

範例指令

用特定config來建立一個service

新增新的config來取代舊的,並更新有用到該config的service

stack file,3.3之後才支援config

Docker Swarm 進階實戰 (1)

  • Ops
tags: docker, devops

Docker Swarm進階實戰(1)

容器的更新

在不移除及重啟容器的情況下更新,從以下指令選項可以知道,container update旨在控制和限縮該容器的資源

另外要清楚的是我們透過docker run執行一個容器,其狀態就只有RunningShotdown兩種,如果出了差錯,此容器不會也不該有任何操作可以重新建立自己

Service的更新

  1. 再來看service update的選項,很明顯比容器更還多出許多操作,因為swarm service存在的目的就是要能在不影響服務的情況下取代(replace)、重建recreate容器

  2. swarm mode也是利用這種方式,逐一取代service底下執行的容器,達到滾動更新

  3. docker service的指令並非直接告訴系統去新增或刪除容器,而是新增了一連串的工作到佇列中,整個處理的流程帶有scale、rollback、failure mitigation等功能

  4. service更新的目標是limit downtime,也就是控制停機時間

  5. stack deploy會觸發service更新

  6. service更新會對nodes做rebalancing

Read More »Docker Swarm 進階實戰 (1)

Docker基礎介紹與實戰

  • Ops

TOC

image

Docker簡介

  • Docker是2013年由DotCloud開發的開源專案,因為軟體的成功,公司之後也改名為Docker.Inc
  • 其實Docker的前身是象龜(@gordonTheTurtle),之後改成鯨魚

Docker的重要性

  • 容器將會是未來最有影響力的基礎架構
  • 不管你是開發、維運、系統管理、部屬都會須要學一下
  • 成長最快的雲端技術
  • Infrastructure as code

Docker的優點

  • 過去底層的基礎架構都是為sysops或sysadmins設計的,但Docker的解決方案考慮了developer的使用情境
  • 就是快:develop faster, build faster, test faster, deploy faster, update faster, recover faster
  • 使用容器來減少不同應用程式、不同系統、不同相依性的複雜度
  • 大部分現存的軟體開發得少維護得多,Docker可以減輕我們維護的難度,增加開發的時間

相關工具

學會了Docker你可能需要多了解其他工具

安裝前要注意的

在不同環境下的安裝:

  • Linux: 直接安裝,不過有分版本
  • Windows: Win10不直接支援,需要透過virtual machine來安裝,在安裝的流程中會設定到;因為Windows Containers的出現,新的Windows Server 2016之後會開始直接支援Docker,不用再透過Linux Container
  • Mac: 也是要透過vm,據說不要用brew來裝
  • Cloud: Docker for GCP/AWS/Azure

看更多有關windows container:

Stable vs Edge(beta)

開源版本的Edge每個月會更新一次,Stable大概四個月更新一次,付費的企業版本會有更穩定的支援

安裝

Windows 10 Pro / Enterprise

  • 使用Pro跟Enterprice的用戶算是比較吃香,會有比較好的體驗
  • 請在此下載安裝Docker for Windows
  • 命令界面(CLI)會建議使用PowerShell
  • 如果你的系統已經有在使用VirtualBox或VMware,Hyper-V啟用可能會發生資源互搶的問題

Windows 7, 8, or 10 Home Edition

  • Win7, 8與Pro/Enterprise的主要差別是Hyper-V過舊不支援,Win10 Home則是沒有Hyper-V,因此要額外安裝Docker Toolbox,然後透過VirtualBox安裝Linux VM(Linux Container),也就是 docker-machine 使用網路位址轉換(NAT)存取網路
  • 需要把Toolbox的 http://localhost 改成 http://192.168.99.100

Mac

  • OSX Yosemite 10.10.3以下版本的需要裝Toolbox,以上版本安裝Docker for Mac

Linux

  • 不要用系統預設的packages直接下指令安裝,例如 apt install docker.io,你可能會裝到過舊的版本
  • 可以經由Docker automated script來安裝相依的程式,例如 curl -ssl https://get.docker.com/ | sh
  • 或者先看過官網上的要求來手動下載安裝檔

Docker會動用到系統核心的功能,需要root權限來操作 你可以將使用者加入Docker group,註:有些版本的linux如Red Hat, Fedora沒有此選項,每個指令都要透過 sudo

Docker Machine & Docker Compose

Windows和Mac會自動幫你安裝好,Linux系統則要自己安裝這兩個項目

Docker compose

使用官方文件提供的指令可能會安裝到非最新的Docker compose版本,你可以到github/docker/compose去安裝最新的版本

版本格式

現今版本的格式為 YY.MM,如 18.06.0 就是2018年6月出的版本的第一個release

其他選項

你可以試試Play with Docker,無須安裝任何環境就可以透過瀏覽器體驗Docker的強大,可以參考以下文章:

指令格式

舊的指令格式為:docker <command> (options),例如 docker run,而新的Docker指令的格式已改成:

例如 docker run 現在要寫成 docker container run,不過舊的指令格式目前還能使用

安裝完成你可以試著執行以下指令:

  • docker: 檢視所有管理選項
  • docker version: 確認你可以跟docker engine溝通,和檢查你的版本號
  • docker info: 檢視docker engine的各項設定值
  • docker image ls: 檢視本機所有映像檔
  • docker pull <-- IMAGE -->: 取得映像檔

容器(Containers)

什麼是容器

容器是基於特定映像檔所創造出來的程序

映像檔(image)和容器(container)的差別

  • 映像檔是我們想執行的應用程式的模板,一個映像檔可以包含一個完整的作業系統環境,裡面安裝了需要的應用程式,同一個映像檔可以建立多個容器
  • 容器是從映像檔建立的執行實例,可以被啟動、開始、停止、刪除
  • 大部分的映像檔都可以從Docker Hub下載並取用

基本指令

  1. 從Docker Hub下載nginx映像檔
  2. 建立一個映像檔實例(容器),命名為webhost1並執行
  3. Port Forwarding: 啟用主機的80 port並將容器內部使用的80 port映射到主機上

註:

  • nginx server預設的對外端口是80 port
  • 你可以更改要映射到主機的哪個port,例如 8888:80,然後用 localhost:8888 訪問

加入detach參數只在背景執行,並回傳容器的id

顯示目前所有容器

關閉正在運行的容器

顯示webhost2的log

檢視webhost2的程序,或檢查是否有正在運行的webhost2

強制關閉運行中的容器

以上這些指令發生了什麼事

docker container run

  1. 尋找特定的映像檔快取,找不到該映像檔的話會從遠端倉庫(remote image repo)尋找(預設是Docker Hub,若沒提供映像檔版本將下載最新的版本)
  2. 新增映像檔實例(容器)
  3. Docker引擎會給這個容器一個實體IP(virtual ip)
  4. 啟用host的特定埠號將容器的特定埠號映射到host
  5. 以映像檔的Dockerfile CMD來執行容器

容器(container)和虛擬機(virtual machine)的差別

很多介紹容器的文章把容器拿來和vm比較,雖然它們相似的地方很多,但事實上它們是完全不同的概念,因為:

  • 容器只是程序(processes)
  • 容器可用的資源是受限的
  • 容器關閉=程序停止

舉個例子來說:

檢視此容器是否正在運行

檢視所有運行中的docker容器,註:docker ps 會對象是host,如果系統是mac或windows,需要先連到docker vm

檢視系統上所有程序,可以清楚的看到容器是一個系統上正在執行的程序

練習:開啟多個容器

  1. 執行一個nginx實例,在背景執行且聽80port
  2. 執行一個httpd(apche)實例,在背景執行且聽8080port
  3. 執行一個mysql實例,在背景執行、密碼設定為自動產生,聽3306port

檢視這三個容器的狀態

檢視mysql密碼

基本指令:監控執行中的容器

檢視容器的設定(metadata),會回傳json陣列

檢視所有容器的即時狀態(live performance)

基本指令:在容器中使用終端機

  • run -t: Allocate a pseudo-TTY
  • run -i: Keep STDIN open even if not attached

根據格式 docker container run [OPTIONS] IMAGE [COMMAND] [ARG...],在指令後面可以再帶入 [COMMAND] 及參數 [ARG...],以nginx為例,預設程式(default program)是 nginx,參數是 -g'daemon off;'

加入bash參數來改變預設程式,進入bash shell之後exit,可以看到容器隨之停止:

這邊可以看出預設的程式變成bash:

  • start -a: Attach STDOUT/STDERR and forward signals
  • start -i: Attach container’s STDIN

重啟容器,注意這裡一樣會開啟bash shell因為我們建立容器時就把command改成bash了:

如果容器正在執行中,我們如何透過殼程式操作呢(這很常用,在容器執行時debug或設定參數):

  • exec: 在執行中的容器上執行額外的程序
  • exec -t: Allocate a pseudo-TTY
  • exec -i: Keep STDIN open even if not attached

另外要注意的是,並非所有映像檔都有bash程式,例如Linux的超迷你分支alpine[ 延伸閱讀 ]:

要使用bash要先透過alpine內建的殼程式sh來安裝

Docker背後的網路運作

docker讓你可以建立虛擬網路(virtual network),並將container加到網路內,建立起屬於你自己應用程式的網路拓墣 [來源]

docker daemon運作的時候,會建立三個網路

當你建立容器時,使用的ip跟主機並不同,例如以下例子:我的主機內部ip是 192.168.43.63,而我的nginx容器的內部ip則是 172.17.0.2

它們之間透過docker birdge network的模式(預設),此模式透過一個叫docker0的NAT server來掌管容器的網路連線 image [圖片來源]

透過以下指令可以看出bridge網路裡有哪些容器

新增一個網路(預設是bridge driver),然後建立新的容器

連結容器至多個網路

DNS設置

容器隨著不同設置會改變其狀態,容器間用ip位址來連線是不可靠的,因此我們會需要DNS server

先來看看新網路的DNS能不能運作

同樣在nginx容器安裝ping套件後,測試能不能雙向溝通

註:如果我以上的測試在預設的bridge network做的話會出現錯誤訊息 Name or service not known,原因是預設的bridge網路並沒有內建的DNS server,容器要連線必須手動使用 --link 指令為容器設定連線到bridge網路。建議建立新的網路來省去這一步驟

練習:快速更新Linux分支的CLI套件

  1. 分別檢查容器不同分支的Linux上的curl版本
  2. 分別在centos:7和ubuntu:14.04的容器中開啟終端機

分別取得各版本的映像檔

建立ubuntu映像檔實例,開啟終端機並檢查curl版本

container run --rm: exit之後預期容器被移除

建立centos映像檔實例,開啟終端機並檢查curl版本

練習:輪替式DNS(DNS Round Robin aka poor man’s load balancer)

  1. 建立一個network包含兩個elasticsearch:2的映像檔實例
  2. 將兩個容器的網路拓墣別名(network-alias)都命名為search

透過一個內網centos容器來測試連線

curl -s: Silent mode. Don’t output anything

映像檔(image)

什麼是映像檔?根據官方定義跟我隨翻:

An image is an ordered collections of root filesystem changes and the corresponding execution parameters for use within a container runtime

映像檔 = 檔案系統變動的有序集合 + 執行一個實例時相對應的執行參數

  • 不是作業系統、沒有內核(kernal)、沒有核心模組(kernal module)[ 延伸閱讀 ]
  • 體積非常輕量,小則幾KB(golang static binary),大則幾GB(ubuntu distro + apache + php)

Docker Hub

目前最多人用的映像檔的集散地(image registry),映像檔repo分成 officialnon-official,映像檔會用 tag 做區別(正確來說tag不算版本或分支),舉例來說,官方的nginx repo:

  • 1.15.5, mainline, 1, 1.15, latest (mainline/stretch/Dockerfile)
  • 1.15.5-perl, mainline-perl, 1-perl, 1.15-perl, perl (mainline/stretch-perl/Dockerfile)
  • 1.15.5-alpine, mainline-alpine, 1-alpine, 1.15-alpine, alpine (mainline/alpine/Dockerfile)

分別pull下來,可以看出同一個映像檔(相同image id)可以有多個tags

Docker Hub的操作跟Github很類似,可以fork其他repo或是上傳新的repo,你所需要的資訊也都能在detail page或github上找到。

  • 映像檔可以從Github或Bitbucket的repo來建置,從首頁點選 Create Automated Build 連結帳戶即可
    • 可以選擇你的映像檔要從哪個分支來build
    • 對於dockerfile的 FROM 指令,Docker Hub可以設定Repository Links,設定連結後,來源映像檔如果有偵測到更新,你的映像檔就會跟著rebuild
    • 自定義Rebuild的Trigger

Union檔案系統(Union file system) && 映像檔的資料層(Image layers)

映像檔的形成並非一個大的資料區塊,例如當我pull nginx:alpine時,可以看到有些資料層我已經有了

透過 image history 來檢視映像檔的資料更動紀錄:

註:IMAGE ID為 <missing> 只是為了區別——這些資料層不完整代表這個映像檔,只是被這個映像檔所用

所有映像檔都是繼承於特定基礎映像檔(blank layer, scratch),再往上繼承堆疊,不同映像檔之間可以共享基礎的檔案系統層,提升儲存效率 [ 延伸閱讀 ]

image [ 圖片來源 ]

image [ 圖片來源 ]

透過 image inspect 來檢視映像檔的metadata,可以看到這個映像檔開了哪些port、有哪些環境變數以及建立的時候會執行的指令等

fork一份映像檔到自己的repo

註:

  • 在遠端機器使用 docker login 的時候,操作完要登出才會移除機器上儲存的密碼
  • 欲上傳private映像檔要先建立一個私人的repo

Dockerfile基本指令

範例1

  • FROM: 開頭一定要加的,指定一個 Base Image 來初始化,通常是取用較輕量的分支如alpine
  • ENV: 設定環境變數
  • RUN: 每行指令都會往上建築新的 layer(new layer on top),上面的範例用 && 來連結每一行指令是常見的作法
  • EXPOSE: 容器沒有任何預設開啟的TCP/UDP埠號,而加了也不代表這些埠號會自動打開,要開啟埠號還是要透過 container run -p
  • CMD: 容器執行或停止的時候都會執行的指令 註:docker能自動幫我們處理logging,上面的範例將log送到stdout跟stderr,讓docker可以捕捉到這些log然後做後續處理

在dockerfile所在的目錄下build image

稍微更改一下dockerfile再安裝一次,可以看出union file system怎麼運作的,dockfile頂端指令會動到的資料幾乎沒什麼變動:Using cache,而越接近後頭的指令,會有較多的變動

範例2

  • 如果你能從更末端的映像檔來build,例如 FROM 官方的nginx再做一些客製化,在維護dockerfiles時就會更加容易。如範例A到範例B
  • WORKDIR: 意同 RUN cd /some/path,不過使用 WORKDIR 會更好
  • COPY: 這個範例用本地的index.html複寫原本nginx的index.html
  • 這個範例並沒有改寫 CMD,這個指令會繼承 nginx:latest 的command

建立一個容器,訪問主頁面時預期會看到客製後的index.html

練習:建立Dockerfile(alpine + node.js + tini)

發布到Docker Hub

持久化數據(Persisting Data)

容器的設計理念有兩個特性:

  1. immutable intrastucture: 當你需要更改設定,皆是透過重新建立新的容器
  2. ephemeral:無狀態,代表容器可以被關閉、銷毀或取代

延伸閱讀: Pets vs Cattle Analogy

容器的特性帶來可靠性(iability)和一致性(consistency),不過相對地帶來一個問題,即如何維持持久化數據(如資料庫),針對這種關注點分離(Seperation of concerns, SOC)的架構設計問題,Docker提供了幾個方案:

  1. Volumes: 由Docker管理,存儲在宿主機的某個地方(在linux上是/var/lib/docker/volumes/)。非Docker應用程序不能改動這一位置的數據。Volumes是Docker最好的數據持久化方法
  2. Bind mounts: 數據可以存放在宿主機的任何地方。數據甚至可以是重要的系統文件或目錄。非Docker應用程序可以改變這些數據;適用於local 開發測試
  3. tmpfs mounts: 數據只存儲在宿主機的內存中,不會寫入到宿主機的文件系統 [ 來源 ]

image

Volumes

先來看一下mysql:8 Dockerfile的 VOLUME 指令

意即當mysql的容器建立的時候,docker會在本機上新增一個 volume location 然後跟容器裡的數據目錄互通,這兩個路徑指向host同一個位址,資料只有靠手動方式才能移除,不會隨著容器被移除而消失

建立一個mysql容器然後看metadata

可以看到data儲存在主機 /var/lib/docker/volumes/c7eaf7ddfa3ad5d90abbe0372d628f97ddcc2384dae45a35d60c74bfdac37416/_data 的位置

而這在使用上會比較不友善:沒辦法從volume看出哪個容器是連結到自身

這裡稍微改善的方式是用參數 -v 為volume命名(以專案來命名之類的)

source的path也變得比較乾淨易讀

另外Volume也可以是匿名的(anonymous volume),會分配一個隨機的名字,在同一個主機中不會重覆[ 官方文件 ]

Bind Mounting

  • host優先於container
  • 不能在Dockerfile裡使用,只能透過 container run
  • 通常是用 -v 指令,或 --mount,格式為 /path/host:/path/container,如

範例

新增一個nginx容器,把 /home/ssivart/桌面目錄mount至容器的 /usr/share/nginx/html

接著我在 /home/ssivart/桌面新增一個index.html,內容為 <h1>Hello World! Bind Mount</h1>

預期在localhost:80會看到我更改過的首頁內容

-v--mount 的差別[ 文件 ]

現在這兩個指令差別僅在於如果host上目錄不存在,使用 -v 會幫你建立新的目錄,使用 --mount 會顯示錯誤

練習:postgres版本更新用Volumes保持數據

練習:使用Bind Mount架設ruby + jekyll[ 來源 ]

Docker Compose[ 官方文件 ]

  • 應用程式常常需要結合多個容器如SQL、proxy、網頁和後端排程等,docker compose便是用來設置容器之間的關係
  • 一鍵完成
  • 可以透過Docker Swarm 1.13以上版本部屬compose file

Docker compose包含兩個部份:

  1. docker-compose.yml: YAML格式的文件來設定容器、網路、Volumes的hierarchy
    • 有區分版本,如1, 2, 2.1
    • -f 來讀取特定檔案,預設讀取的檔名是 docker-compose.yml
  2. docker-compose: 命令列(CLI)工具用來測試compose file

以下是compose file範例:

一個簡單的proxy network設定如下

docker compose CLI

  • 請參考上方提到的安裝流程
  • 僅用於開發測試端,非正式部屬使用

常用指令

  • docker-compose up: 設定volumes/networks,執行所有容器,使用 -d 讓程序於背景執行
  • docker-compose down: 停止並移除所有容器,常用 -v 來移除所有volumes/networks

練習: drupal + postgres架站

使用compose來建置(build)客製化映像檔

  • 使用 docker-compose up,如果找不到該映像檔的cache,會在當下建置
  • re-build使用 docker-compose up --builddocker-compose build

先來看以下compose範例:

當proxy容器執行時,會先在cache找nginx-custom這個映像檔,找不到會build,這邊示範了在 context 提供的目錄下用 dockerfile 來建置映像檔

執行完 down,docker並不會主動移除客製化映像檔,針對要移除上面範例經過命名的映像檔,down 指令加上 --rmi all 參數,如果是不提供映像檔名稱,docker會以 <bulid directory>_<container name> 的規則來命名映像檔,可以透過 --rmi local 移除

composefile配置

這個部份官方還在持續更新 往後針對部署端的compose還會有許多變動(swarm、stack、secrets…),之後會持續更新

docker-compose會自動辨識.override.yml 的檔案,.test.yml.prod.yml 或其他自訂的compose file則需要手動透過指令 -f 來操作

本地開發端:docker-compose.yml + docker-compose.override.yml

CI測試:docker-compose.yml + docker-compose.test.yml

部署通常會用 config 輸出成一個完整的compose file:docker-compose.yml + docker-compose.prod.yml

Swarm Mode

  • Swarm用來做(叢集)架構管理
  • Swarm內建於Docker
  • 多個Docker host組成1個Swarm mode
  • Swarm程式獨立於Docker,在Docker環境下透過swarmkit運行(須先啟用)

Node

Swarm中的Docker的實例(Docker host)

image

  • Worker:
    • 負責容器的執行
  • Manager:
    • 在Swarm中透過Raft Database的設定進行協調與同步
    • 負責管理Worker與協調容器的部署工作
    • 也可以當Worker,Manager可以想像成有Swarm控制權限的Worker

兩個角色可以互換,node之間透過雙向TLS(mutual Transport Layer Security, 前身是SSL)協定溝通

image

Service and Task

  • Task: Container + Command(怎麼run這個容器)
  • Service: Task A + Task B + Task C(任務的堆疊),基於 docker run 的再封裝

Swarm會確保services持續運作

在新的處事方式上,服務器被編好號,就像牛在牛群中。比如,www001到www100。當一個服務器宕機了,它將會被取出替換上線 —— Randy Bias

image

Swarm運作

image [ 圖片來源 ]

基本指令

docker swarm init 可以新增一個swarm,其中完成這些動作[ 文件 ]

  1. 初始公開金鑰基礎架構(public key infrastructure, PKI)
    • Docker先扮演第一個Manager node(root manager)
    • 產生一組root certificate authority(.ca)
    • 產生token: worker token + manager token
    • 其他node可以用這組token加入(join)swarm
  2. 初始Raft database
    • 儲存憑證
    • 在control plane讓Manager之間共享log,透過TLS
    • 儲存config data[ 文件 ]

初始後可以看到第一個manager node

建立一個service,指定task的容器執行的指令及參數(docker run)

檢視service的task,可以看到一個執行中的容器

更新service的參數,提高task數量(replicas)來sacle up

手動停止其中一個容器,service會再add一個task到service queue取代之,確保同時會有3個正常運作的task

要終止task必須移除整個service,同時會把當中所有的程序清理掉

更新services

指令範例

service更新其中的tasks都會重建,task建立時docker會挑負載較小的node做較多分配,所以對service做 force update 可以平衡node之間的負載

CLI更新

service createservice update 在不同版本上的參數變更:

  1. 17.05前:必須都要透過 service lsservice ps 來檢查是否正常執行
  2. 17.05後:新增了 --detach 參數,預設為true
  3. 17.10後:--detach 參數,預設改為false 結論是17.12版本後要透過shell scripts或automation來建立service的話,記得設定 --detach=true

使用GCP Compute Engine Instance Group來試作多節點Swarm

worker node沒有swarm的控制權

提昇host的worker成manager,node狀態變成Reachable

Overley Network

跨Node間的網路拓樸,基於Routing Mesh

psql在node1,drupal在node2,node2可以透過dns name:psql來存取node1的資料庫,用80 port連到node1也能看到drupal的歡迎頁面

Routing Mesh

  • 為service底下的task提供路由(routes ingress packets)
    • container-to-container use Virtual IP
    • external traffic incomming to publish ports(all nodes listen)
  • 為services提供負載平衡
    • stateless load balancer,如果需要指向特定container的話,須另外設定(如cookie、session)
    • 使用linux既有的IPVS(IP Virtual Server)實現load balancing
    • load balancer表現於TCP層的(OSI第3層),針對一個swarm一個對外port的web架構,還會需要Nginx、HAProxy來做DNS層(第4層)的load balancer
  1. 無論訪問網路中的哪個節點,即使該節點上沒有運行該service的副本,最終都能訪問到該service 舉例來說,如果後端資料庫有3個副本,當前端web server要取資料時,並非直接訪問某個資料庫副本的ip,而是透過swarm為所有service搭建的Virtual IP(VIP)
  2. 外部流量導向所有節點共同監聽的public port

image

image

練習:voting app[ dockersamples ]

image

首先先建立前後端的網路,跨node要用overlay模式

Stacks

  • dockerfile版本3以上
  • 適用於部署端的compose(services + volumes + overlay networks + secrets…)
  • composefile指令跟local端的差異:開發端忽略 deploy 指令,部署端忽略 build
  • 部署不透過docker-compose
  • 針對已經存在的service,再部署會update這些service

上述的範例只要透過一個Composefile就能完成所有部署

swarm的可視化工具visualizer

image

Secrets

  • 儲存:
    • 使用者帳密
    • TLS憑證、金鑰
    • SSH金鑰
    • 自訂設定檔
  • 支援動態字串或二進位的內容
  • 儲存在Raft database,只存在於各個manager node的硬碟空間
  • secrets產生後會先存在swarm再分配到特定service,只有特定的container能訪問
  • 乍看之下是個實體檔案,但實際上是ramfs files system透過記憶體儲存
  • secrets只適用於swarm,而swarm只適用於部署端(production),但docker讓docker-compose也能使用,僅提供開發測試,不具真的功能(fake secure)

secrets無法透過指令檢視內容(廢話),容器要存取secret得先經過指定

但這樣還少了怎麼配置這些secret,docker提供一個方便的查找方式,前提是映像檔要有這些變數

終端機進容器檢視密碼

針對已經建立的service可以透過 update --secret-rmupdate --secret-add 來更新secret,但這樣做會導致整個service重新部署

secrets透過stack部署

  • dockerfile版本3.1以上

透過實體檔案儲存密碼的方式是有風險的,記得在部署完成後移除這些檔案

開發端測試secrets

  • docker-compose CLI版本11以上適用
  • 開發端是使用bind mount的方式把secrets mount到本機目錄,只是用於開發並無secret實際功能
  • 不適用內含external用法,如果部署是用 external:true,可以另外維護一個開發用的compose file,secret的部份改用file來寫入

Healthchecks

  • 回傳0(OK)或1(Error)
  • 支援Dockerfile、Compose、docker run 及swarm services
  • 容器有三種健康狀態: starting, healthy, unhealthy

container

services

Docker Registry

push之後映像檔的實體檔案儲存在/var/lib/registry/

Registry in Swarm mode

  • 主要問題是解決nodes之間要訪問同一份映像檔
  • 如果只在其中一個manager node build image,其他node是沒辦法取得該image
  • 解法:
    • 使用Docker hub、AWS、Quay來儲存管理映像檔
    • 借助Routing Mesh,所有node都能藉由127.0.0.1:5000訪問

以下示範如何使用Routing Mesh建立registry

將映像檔push到registry後,所有nodes都能從127.0.0.1:5000取得映像檔