# Docker Note
###### tags: `docker`
[Docker ARG, ENV 有什麼不同](https://blog.scottchayaa.com/post/2018/11/04/docker-arg-env-variable/)
Docker Compose:
用 yml 定義多個容器連結方式的解決方案
----
[30 天與鯨魚先生做好朋友](https://ithelp.ithome.com.tw/users/20102562/ironman/3746)
Terms in Docker:
- image
- container
- host
- repository
背景執行 container `-d`
```
docker run -d httpd
```
## Prot forwarding
container 具有隔離特性,也就是每個 container 都是獨立的個體,它們各自有屬於自己的 80 port 可以用,因此才不會相衝。
今天的目標是要從外界存取 container,因此要做點手腳才行--正是標題提到的 port forwarding。Docker 使用 -p 選項設定 port forwarding,範例如下:
```bash=
# 加上 -p 參數
docker run -d -p 8080:80 httpd
# 確認 port 有被開出來了
curl http://localhost:8080/
```
## Volume
Volume 也是 Docker 的元件,它提供 container 保存資料或共享資料的機制。
開啟 container 後,可以進到 container 裡去做操作。例如進到 httpd container 中去修改靜態網頁內容。
但這個做法,每次開新的容器後又會刷新,所以可以綁定 host 和 container 的路徑,讓容器可以存取。
Bind Mount
```bash=
# 執行 container
docker run -d -it -v `pwd`:/usr/local/apache2/htdocs -p 8080:80 httpd
# 測試對應路徑
curl http://localhost:8080/test.html
```
## Network
Network 也是 Docker 的元件
有了 Docker 後,開 server 變得容易許多。但實務上的網路架構,通常是多層式的,如三層式架構(Three-Tier)需要 Application Server 與 RDBMS 兩種 server 連結起來,才能提供完整的服務。
### 觀察背景執行的容器
```
# Terminal 1
docker run -d -it --name web -p 8080:80 httpd
# 加 -f 選項後,container log 只要有更新,畫面就會更新
docker logs -f web
# Terminal 2
curl http://localhost:8080/
```
### Connect containers
```bash=
# wget 為 curl 的替代指令
docker run --rm busybox wget -q -O - http://web/
# 比較沒加 link 與有加 link 的差別
docker run --rm --link web busybox wget -q -O - http://web/
# 使用別名
docker run --rm --link web:alias busybox wget -q -O - http://alias/
```
執行 BusyBox 的 wget -q -O - http://web/ 的 web 對應的是 Apache container 的 --name web 設定。另外,必須要使用 container 內部的 port(本例是 80)呼叫。
--link 選項的用法:web:alias 左邊是 container name,右邊是別名。設定完後,web 和 alias 都能通。
### Use network
```bash=
# 建立 network
docker network create my-net
# Terminal 1 啟動 Apache
docker run --rm --name web -p 8080:80 --network my-net httpd
# Terminal 2 透過 BusyBox 連結 Apache
docker run --rm --network my-net busybox wget -q -O - web
```
`-O` output file. If no given, no file will be saved
`-q` quit. If this on, no download status will display
### -\-link 的問題
>The Linked can't interact with the linker.
### Summary
- `link` only has one direction
- `network` a container can connect to each others in a same Network

## Enviroment
```bash=
# 查看原本的 env
docker run --rm busybox env
# 給 env 設定後再看 env 的內容
docker run --rm -e DB_HOST=mysql busybox env
```
### Build a phpmyadmin connected to DB
```bash=
# Terminal 1,使用 MYSQL_ROOT_PASSWORD 與 MYSQL_DATABASE
docker run --rm -it --name db -e MYSQL_ROOT_PASSWORD=password -e MYSQL_DATABASE=demo mysql/mysql-server
# Terminal 2
docker run --rm -it --link db -p 8080:80 phpmyadmin
```
> Host XXX is not allowed to connect to this MySQL server -> https://github.com/docker-library/mysql/issues/275
Check user and host
```sql=
SELECT host, user FROM mysql.user;
```
So let's add a new user
CREATE USER 'user'@'%' IDENTIFIED BY 'password';
The first thing to do is to provide the user with necessary permission and here I have given all permission to the particular user.
```sql=
GRANT ALL PRIVILEGES ON * . * TO 'user'@'%';
Reload all the privileges.
```
Remeber to flush privileges after alter privileges
```sql=
FLUSH PRIVILEGES;
```
If you want to allow range of IPs to a particular user use as follows 10.1.1.%
```sql=
GRANT ALL PRIVILEGES ON * . * TO 'user'@'10.1.1.%';
````
> Note: Here host Name = % and that means you can access this database server from any host. Granting all privileges to the user is a big risk and that's not a best practice. Further you can replace user 'user' to 'bob'.
docker-compose reference for mysql:
https://github.com/docker-library/mysql/issues/275
## 應用
- 遠端資料庫版本多樣,本端不用安裝對應版本,而是用容器連線
- 測試同一份 source code 在不同版本語言下測試
- 不用安裝一些非常用軟體、語言但還是可以用
### 進階懶人
[alias](https://linuxhint.com/configure-use-aliases-zsh/)
```shell=
# 使用 Composer
alias composer="docker run -it --rm -v \$PWD:/source -w /source composer:1.10"
# 使用 npm
alias npm="docker run -it --rm -v \$PWD:/source -w /source node:14-alpine npm"
# 使用 Gradle
alias gradle="docker run -it --rm -v \$PWD:/source -w /source gradle:6.6 gradle"
# 使用 Maven
alias mvn="docker run -it --rm -v \$PWD:/source -w /source maven:3.6-alpine mvn"
# 使用 pip
alias pip="docker run -it --rm -v \$PWD:/source -w /source python:3.8-alpine pip"
# 使用 Go
alias go="docker run -it --rm -v \$PWD:/source -w /source golang:1.15-alpine go"
# 使用 Mix
alias mix="docker run -it --rm -v \$PWD:/source -w /source elixir:1.10-alpine mix"
```
- docker run -w
```
-w|--workdir 指定預設執行的路徑
```
# Docker Compose
Build and run mutiple containers at once
First, we need to learn how to write `docker-compose.yml`, which is a config file that records all setup we desire
Build a database and make phpmyadmin server connect to the database.
```yml
# docker-compose version
version: "3.8"
networks:
net:
services:
db:
image: mariadb:10.3
environment:
MYSQL_ROOT_PASSWORD: pass
networks:
net:
phpmyadmin:
image: phpmyadmin
environment:
PMA_HOST: db
ports:
- 8080:80
networks:
net:
```
create containers and run
```
docker-compose up
```
also delete exited containers
```
docker-compose up --remove-orphans
```
### mysql database 的雷
不同 db 映像檔預設的使用者和權限不一樣,如果要不限 IP 的話,host 要為 % (means any)
- mysql/mysql-server: need to alter
- mariadb: ready to go as build

可以透過 [Privilege 相關的 query](#Build-a-phpmyadmin-connected-to-DB) 調整,也可以直接 update 資料庫
```sql
UPDATE mysql.user SET host = '%' WHERE user = 'root' AND host = 'localhost';
```
調完記得 flush
```sql=
FLUSH PRIVILEGES;
```
更多權限調整:https://phoenixnap.com/kb/how-to-create-new-mysql-user-account-grant-privileges
## Docker commit
最開始,得先了解 Docker image 的基本概念。首先最基本的,Docker 是採用 Union 檔案系統(簡稱 UnionFS)來儲存 image。
- 分層式的檔案系統
- 支援把「檔案系統的修改」作為 commit,讓多個 commit 一層層堆疊
- 支援把多個目錄掛載到同一個虛擬檔案系統下
summary
- 可以克制化
----
信號
http://shihyu.github.io/books/ch33s01.html