# Services with Docker and Compose
## 章節重點
### 理解什麼是 service
> Any processes, functionality, or data that must be discoverable and available over a
network is called a service.
現今的軟體大多都包含了許多子系統,而這些子系統會彼此交互依賴溝通
利用抽象的Service可以幫助我們用更簡單的角度去理解各個系統的職責
Docker也有提供service的功能 (Swarm),幫助我們去管理service的生命週期,
以及協作和調度
### 介紹 Docker Swarm
* 名詞和定義介紹
* Automated resurrection and replication
* Automated rollout
* Service health and rollback
### 利用 Docker Compose 來管理 service
- 介紹YAML格式
- replicas
- volumes
- networks
## Docker Swarm 名詞
[官方概念介紹](https://docs.docker.com/engine/swarm/key-concepts/)
[Manager vs Worker nodes](https://docs.docker.com/engine/swarm/how-swarm-mode-works/nodes/)
* Swarm
> A swarm consists of multiple Docker hosts which run in swarm mode (managers or workers)
* Nodes
> A node is an instance of the Docker engine participating in the swarm
* Service
> A service is the definition of the tasks to execute on the manager or worker nodes
* Task (roughly interchangeable with container)
> A task carries a Docker container and the commands to run inside the container. It is the atomic scheduling unit of swarm.
### Service 和 Task(container) 的區別
> service的功能會由一群containers來負責實作
![](https://docs.docker.com/engine/swarm/images/services-diagram.png)
## Swarm 的功能介紹
### 前置步驟
```
// 把自己的機器變成一個 node
docker swarm init
// 啟動範例 service
docker service create \
--publish 8080:80 \
--name hello-world \
dockerinaction/ch11_service_hw:v1
```
### Automated resurrection and replication
> swarm 可以自動保持 service 的 DESIRED STATE
> swarm 可以實現 service 的水平擴展
> 偵測維持 replicas 的設定,自動啟動或關閉 tasks(containers)
#### 查看 service
```
// list service
docker service ls
// list the container associated with a specific service
docker service ps hello-world
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
bm217mfvfeqa hello-world.1 dockerinaction/ch11_service_hw:v1 docker-desktop Running Running 2 minutes ago
lnnk5tc3l768 \_ hello-world.1 dockerinaction/ch11_service_hw:v1 docker-desktop Shutdown Failed 2 minutes ago "task: non-zero exit (137)"
```
- DESIRED STATE: 希望的狀態
- CURRENT STATE: 系統當前狀態
#### 查看 service 的設定
```
docker service inspect --pretty hello-world
docker service inspect hello-world
```
https://docs.docker.com/engine/swarm/swarm-tutorial/rolling-update/
> Rollout parameters => UpdateConfig
```
ID: oqo4kuy9zq6p7ys41mhyg2sb6
Name: hello-world
Service Mode: Replicated
Replicas: 1
Placement:
UpdateConfig:
Parallelism: 1
On failure: pause
Monitoring Period: 5s
Max failure ratio: 0
Update order: stop-first
RollbackConfig:
Parallelism: 1
On failure: pause
Monitoring Period: 5s
Max failure ratio: 0
Rollback order: stop-first
ContainerSpec:
Image: dockerinaction/ch11_service_hw:v1@sha256:4f92ec42207773b4ea97afe03469ff30598d08dd2ec4a28e05550b3ba4bc5fd5
Init: false
Resources:
Endpoint Mode: vip
Ports:
PublishedPort = 8080
Protocol = tcp
TargetPort = 80
PublishMode = ingress
```
#### 水平擴展 service
[service_scale](https://docs.docker.com/engine/reference/commandline/service_scale/)
[replicated vs global](https://docs.docker.com/engine/swarm/how-swarm-mode-works/services/)
[swarm ingress](https://docs.docker.com/engine/swarm/ingress/)
- Two types of service deployments
- replicated (specific replica number)
- global (one replica on each node)
```
docker service scale hello-world=3
docker service ps hello-world
```
### Automated rollout
> swarm 可以自動更新 service
[service_update](https://docs.docker.com/engine/reference/commandline/service_update/)
![](https://i.imgur.com/xgNDXnZ.png)
```
docker service update \
--image dockerinaction/ch11_service_hw:v2 \
--update-order stop-first \
--update-parallelism 1 \
--update-delay 30s \
hello-world
```
- update-parallelism 1
```
Service Mode: Replicated
Replicas: 3
UpdateStatus:
State: completed
Started: 2 minutes ago
Completed: 35 seconds ago
Message: update completed
Placement:
UpdateConfig:
Parallelism: 1
Delay: 30s
On failure: pause
Monitoring Period: 5s
Max failure ratio: 0
Update order: stop-first
```
- update-parallelism 3
```
Service Mode: Replicated
Replicas: 3
UpdateStatus:
State: completed
Started: About a minute ago
Completed: 18 seconds ago
Message: update completed
Placement:
UpdateConfig:
Parallelism: 3
Delay: 30s
On failure: pause
Monitoring Period: 5s
Max failure ratio: 0
Update order: stop-first
```
### Service health and rollback
>A successful partnership with an orchestrator means clearly communicating the
expected requirements and behavior of the workload you’re asking it to orchestrate
- update 成會失敗的版本
```
docker service update \
--image dockerinaction/ch11_service_hw:start-failure \
hello-world
```
```
overall progress: 0 out of 3 tasks
1/3: starting [============================================> ]
2/3:
3/3: starting container failed: OCI runtime create failed: container_linux.go:3…
service update paused: update paused due to failure or early termination of task fjk5wq3ntlby27w7i5wlpdoy6
```
- 手動 rollback 到上一版
```
docker service update \
--rollback \
hello-world
```
- 在 update 的時候指定 update-failure-action
- update-failure-action: ("pause"|"continue"|"rollback")
```
docker service update \
--update-failure-action rollback \
--update-max-failure-ratio 0.6 \
--image dockerinaction/ch11_service_hw:start-failure \
hello-world
```
```
overall progress: rolling back update: 3 out of 3 tasks
1/3: running [> ]
2/3: running [> ]
3/3: running [> ]
rollback: update rolled back due to failure or early termination of task y0ltb7g7a7q7ons8kjb9gjw2r
verify: Service converged
```
#### Docker 如何檢查 task 的 health
>Docker is application agnostic. Rather than making assumptions about how to
determine whether a specific task is healthy, it lets you specify a health check command
- **HEALTHCHECK** in Dockerfile
https://hub.docker.com/r/dockerinaction/ch11_service_hw/tags
```
HEALTHCHECK --interval=10s CMD ["/bin/httpping"]
```
- 也可以透過 update 指定 health check 的設定
```
docker service update \
--health-cmd /bin/httpping \
--health-interval 10s \
hello-world
```
[update 的 options](https://docs.docker.com/engine/reference/commandline/service_update/#options)
## Declarative service environments with Compose V3
>Setting all of these parameters when you’re managing a service from the command
line is a mess
![](https://i.imgur.com/EzmqGni.png)
- Docker Compose File 的優點
- 避免人為的下指令減少犯錯機會
- 更有系統的去設定 service 的參數
- 可以做版本控制 (git)
- Docker Compose File 的缺點
- 相較於指令會不夠靈活
> When you need to model a whole environment of services, you should use a Docker
stack. A stack describes collections of services, volumes, networks, and other configuration abstractions.
### A YAML primer
https://zh.wikipedia.org/wiki/YAML
### Collections of services with Compose V3
https://docs.docker.com/compose/compose-file/compose-file-v3/
```yml
version: "3.7"
services:
postgres:
image: dockerinaction/postgres:11-alpine
environment:
POSTGRES_PASSWORD: example
mariadb:
image: dockerinaction/mariadb:10-bionic
environment:
MYSQL_ROOT_PASSWORD: example
adminer:
image: dockerinaction/adminer:4
ports:
- 8080:8080
```
### Creating and updating stack
- create
```
docker stack deploy -c databases.yml my-databases
```
- update
```
adminer:
image: dockerinaction/adminer:4
ports:
- 8080:8080
deploy:
replicas: 3
```
### Scaling down and removing services
- scale down
```
adminer:
image: dockerinaction/adminer:4
ports:
- 8080:8080
deploy:
replicas: 2
```
- remove service
把 mariadb 的 definition 刪掉
```
# 比較不好的方式 但可以成功移除
docker service remove my-databases_mariadb
```
```
# 比較正確但會刪掉沒有在yaml定義的resources
docker stack deploy -c databases.yml --prune my-databases
```
### Stateful services and preserving data
- 增加volume的設定
```yml
version: "3.7"
volumes:
pgdata:
services:
postgres:
image: dockerinaction/postgres:11-alpine
volumes:
- type: volume
source: pgdata
target: /var/lib/postgresql/data
environment:
POSTGRES_PASSWORD: example
adminer:
image: dockerinaction/adminer:4
ports:
- 8080:8080
deploy:
replicas: 1
```
- 重新啟動 service
```
docker service remove my-databases_postgres
docker stack deploy -c databases.yml my-databases
```
### Load balancing, service discovery, and networks with Compose
>Port publishing for a service is different from publishing a
port on a container. Whereas containers directly map the port on the host interface to an
interface for a specific container, services might be made up of many replica containers.
>Docker accommodates services by creating virtual IP (VIP) addresses and balancing requests for a specific service between all of the associated replicas.
![](https://i.imgur.com/zbV8M9N.png)
#### ingress network
- handles all port forwarding from the host interface to services
#### my-databases_default
- Docker will create a network for your stack named 'default', if not define network config in compose file
#### 可以定義自己的 network
- 讓不同的 stack 共用同個 network
- 讓 services 不共用同個 network
https://docs.docker.com/compose/compose-file/compose-file-v3/#network-configuration-reference
```yml
version: "3.7"
networks:
foo:
driver: overlay
volumes:
pgdata:
services:
postgres:
image: dockerinaction/postgres:11-alpine
volumes:
- type: volume
source: pgdata
target: /var/lib/postgresql/data
networks:
- foo
environment:
POSTGRES_PASSWORD: example
adminer:
image: dockerinaction/adminer:4
networks:
- foo
ports:
- 8080:8080
deploy:
replicas: 1
```