<style>
.reveal section img {border:0px;background:0;box-shadow:none;}
.reveal pre {width:1000px;}
.reveal pre code {width:1000px;max-height: 600px;}
.reveal img {max-width:80%;max-height:80%}
.reveal h4 {text-align: left;}
</style>
# Docker
> [name=巫佳溢]
> [time=Thu, Mar 26, 2020 16:00 PM]

---
## Agenda
* ### Docker Concepts
* ### Docker CLI
* ### Docker-compose
* ### Dockerfile
---
## Docker concepts

----
### Docker V.S Virtual machines

----
<style>.reveal table tr td {white-space: nowrap;}</style>
### Dcoker 特性
|||
|--------------|:-----|
|靈活性|複雜的應用程式也可以容器化
|輕量化 |容器共享內核,系統消耗比虛擬機器低
|可移植 |可在本地建構,部署到任何地方運行
|低耦合 |容器間相依低,更換或者升級不會影響其他容器
|可擴展 |可以在數據中心跑多個容器
|安全性 |容器之間預設的網路是不通的
----
### Docker V.S Virtual machines
特性 | Docker | VM |
--------------|:-----:|-----:|
啟動速度 | 秒級 | 分鐘級 |
硬碟使用|一般為MB|一般為GB
性能|接近原生|較差
系統支援量|單機支持上千容器|一般幾十個
隔離性|安全隔離|完全隔離
----
### Docker 三個基本概念
* 映像檔(Image)
* 容器(Container)
* 倉庫(Repository)

----
### 映像檔 Image
#### Docker 映像檔是一個模板,用來重複產生容器。一個映像檔可以包含完整的服務、編譯環境、或是作業系統。
----
### 容器 Container
#### 容器就像是用蛋糕模板烤出來的蛋糕本體,容器是用映像檔建立出來的實體。它可以被啟動、開始、停止、刪除。每個容器都是相互隔離。
----
### 倉庫 Registry
#### 倉庫是集中存放映像檔的地方。倉庫可分為公開倉庫和私有倉庫。官方公開倉庫是 Docker Hub,存放了數量龐大的映像檔供使用者下載
----
### Public Registry 公有倉庫
* [Docker Hub](https://hub.docker.com/)
* [Google Container Registry](https://cloud.google.com/container-registry)
* [Azuer Container Registry](https://azure.microsoft.com/zh-tw/services/container-registry/)
* [Amazon Elastic Container Registry](https://aws.amazon.com/tw/ecr/)
<br>
### Private Registry 私有倉庫
* [Harbor](https://goharbor.io/)
* [nexus-repository-oss](https://www.sonatype.com/nexus-repository-oss)
----

----
### [Install](https://www.docker.com/get-started)

---
## Docker CLI

----

----
* [Docker Commands](https://hackmd.io/XspqgzFTR5-L__CcLfeIPw?view)
* [Image Commands](https://hackmd.io/Tr9NRg0ZTjGI7TAFilLwAA)
* [Container Commands](https://hackmd.io/aSGsPUBIQmeKvNFd_0hu1g)
----
### Docker 常用指令
* [docker run](https://hackmd.io/96J_JkovTCGRwpxFrtin3A)
* [docker ps ](https://hackmd.io/4iwzmaSkQGmOIWWW5LAoIw)
* [docker images](https://hackmd.io/8oW_sXaoTHSbUeLqlzjz7A)
* [docker logs](https://hackmd.io/vodeYqRuRO-0oRp-RaPGcg)
* [docker start](https://hackmd.io/nJvSgubqR5GMqdy73zNfHQ)
* [docker stop](https://hackmd.io/Nii7yy3qQdmayZ6CLBdnA)
* [docker rm](https://hackmd.io/jCZJXnGNQDycyYxPbnBSiw)
* [docker rmi](https://hackmd.io/fHUZsIbbS4STC18TZ7HyzQ)
* [docker exec](https://hackmd.io/9C-CjPUjRTuMYMQ0UHqpOw)
* [docker build](https://hackmd.io/DmmIr4TIS4e3ZAT76o4h-A)
----
### Demo
```bash=
docker version
docker info
docker run ubuntu /bin/echo 'Hello world'
docker run -t -i ubuntu /bin/bash
docker run -d -p 86:80 --rm --name nginx nginx
docker run -p 6379:6379 --rm --name redis redis
docker run busybox echo "Hello world"
docker ps -a
docker logs nginx -f
docker stop nginx
docker start nginx
docker restart nginx
docker rm nginx
docker images nginx
docker rmi nginx
docker exec -ti nginx bash
docker build -t
```
---
## [Docker-compose](https://hackmd.io/qk1Y851mRZ-vz82ZjpUSGg)

----
#### docker-compose.yml
```yml=
version: "3"
services:
db:
container_name: "mysql"
image: "mysql"
volumes:
- "./.data/:/var/lib/mysql"
command: --default-authentication-plugin=mysql_native_password
restart: always
environment:
MYSQL_ROOT_PASSWORD: "root"
ports:
- 3306:3306
adminer:
container_name: "adminer"
image: "adminer"
restart: always
ports:
- 9999:8080
```
----
### Docker-compose 常用指令
* docker-compose up -d
* docker-compose down
* docker-compose start
* docker-compose stop
* docker-compose restart
* docker-compose build
* docker-compose ps
* docker-compose top
* docker-compose images
* docker-compose config
---
## Dockerfile

----
## Dockerfile
### Dockefile 是一個文字格式的設定檔,使用者可以使用Dockerfile來快速建立自己的映像檔。
----
## [Dockerfile指令](https://docs.docker.com/engine/reference/builder/)
```dockerfile=
FROM 基底映像檔
USER 指定執行容器的使用者名稱或者ID
WORKDIR 工作目錄
LABEL 指定維護者資訊
ENV 建立環境變數可供後續使用
ARG --build-arg 帶入變數,讓build可以結合外部指定建構時所需的參數
COPY 複製本機上的資料至容器
ADD 複製指定的url或是tar檔(自動解壓縮)至指定的目錄
VOLUME 建立一個可以從本幾對外掛載的目錄
EXPOSE 宣告此容器Run在哪個 Port
RUN Build layer 中執行的指令,一個Dockerfile中可以有多個RUN
CMD 當容器啟動之後默認會執行的命令,可以有多個CMD,不過只有最後一個會生效
ENTRYPOINT 指定容器啟動程序及參數
```
----
## Dockerfile
```bash=
FROM nginx
WORKDIR /app
EXPOSE 89
COPY index.html /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
```
### [docker build](https://hackmd.io/DmmIr4TIS4e3ZAT76o4h-A)
```bash=
docker build -t mynginx .
```
### docker run
```bash=
docker run -d --rm -p 89:80 mynginx
```
----
## 各指令的差異
----
### ENTRYPOINT VS CMD VS RUN
#### RUN
```bash=
FROM busybox
RUN ["echo", "Hello Dockerfile!"]
```
#### CMD
```bash=
FROM busybox
CMD ["echo", "Hello Dockerfile!"]
```
#### ENTRYPOINT
```bash=
FROM busybox
ENTRYPOINT ["echo", "Hello Dockerfile!"]
```
----
#### ENTRYPOINT + CMD
```bash=
FROM busybox
ENTRYPOINT ["echo"]
CMD ["Hello Dockerfile!"]
```
```bash=
FROM busybox
ENTRYPOINT ["ping"]
CMD ["tw.yahoo.com"]
```
----
### ENTRYPOINT VS CMD VS RUN
* ##### RUN 命令並建立新的鏡像層,經常用來安裝image中需要的軟件。
* ##### CMD 容器啟動後默認執行的命令及其參數,能夠被命令行參數代替。
* ##### ENTIRYPOINT 配置容器啟動時運行的命令。
----
## ENV VS ARG
#### ENV
```bash=
FROM busybox
ENV name=5+1
ENTRYPOINT echo ${name}
```
#### ENV + ARG
```bash=
FROM busybox
ARG MY_ARG=456
ENV MY_ENV=$MY_ARG
ENTRYPOINT echo ${MY_ENV}
````
#### docker build
```bash=
docker build --build-arg MY_ARG=5+1 busy .
```
----
## COPY VS ADD
#### COPY
```bash=
FROM busybox
WORKDIR /app
COPY test.tgz /app
RUN tar -xzvf /app/test.tgz && rm /app/test.tgz
ENTRYPOINT [ "ls" ]
```
#### ADD
```bash=
FROM busybox
WORKDIR /app
ADD test.tgz /app
ENTRYPOINT [ "ls" ]
```
##### [add-or-copy最佳實現](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/#add-or-copy)
----
## Shell forms Vs Exec forms
#### Shell forms
```bash=
FROM busybox
ENV name Andy
ENTRYPOINT echo "Hello, $name"
```
#### Exec forms
```bash=
FROM ubuntu
ENV name Andy
ENTRYPOINT ["/bin/sh", "-c", "echo ${name}"]
```
----
## [Understand how CMD and ENTRYPOINT interact](https://docs.docker.com/engine/reference/builder/#understand-how-cmd-and-entrypoint-interact)

----
### Node Js Dockerfile
```dockerfile=
FROM node:lts as build
WORKDIR /app
COPY package* /app/
RUN npm install
FROM node:lts-alpine as run
WORKDIR /app
COPY --from=0 /app /app/
COPY . /app
EXPOSE 85
CMD [ "npm", "run", "start" ]
```
----
### .Net Core Dockerfile
```dockerfile=
FROM mcr.microsoft.com/dotnet/core/sdk:3.1 AS build
WORKDIR /app
COPY . .
RUN dotnet restore
RUN dotnet publish -c Release -o out
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1 AS runtime
WORKDIR /app
COPY --from=build /app/out .
ENTRYPOINT ["dotnet", "dotnetcore.dll"]
````
----
### 官方 Dockerfile 參考
* #### [golang Dockerfile](https://github.com/docker-library/golang/blob/master/1.14/alpine3.11/Dockerfile)
* #### [redis](https://github.com/docker-library/redis/blob/master/5.0/Dockerfile)
* #### [busybox](https://github.com/docker-library/busybox/blob/master/uclibc/Dockerfile)
* #### [kibana](https://github.com/docker-library/kibana/blob/master/7/Dockerfile)
* #### [nginx](https://github.com/docker-library/nginx/blob/master/1.7/Dockerfile)
---
## 課後動腦
* ##### 1.Dockerfile ENV & ARG 有什麼不同?
* ##### 2.Dockerfile ENTRYPOINT & CMD & RUN 有什麼不同?
* ##### 3.Dockerfile COPY & ADD 有什麼不同?
* ##### 4.Build一個自定義映像檔,Run一個非80port的Web服務,Web畫面上顯示現在時間
---
## Reference
* #### [docker](https://www.docker.com/)
* #### [docker hub](https://hub.docker.com/)
* #### [ASP.NET Core 的 Docker 映像](https://docs.microsoft.com/zh-tw/aspnet/core/host-and-deploy/docker/building-net-docker-images?view=aspnetcore-3.1)
* #### [容器最佳實現](https://docs.docker.com/develop/develop-images/dockerfile_best-practices/)
* #### [Dockerfile指令](https://docs.docker.com/engine/reference/builder/)
* #### [docker-library](https://github.com/docker-library)
{"metaMigratedAt":"2023-06-15T09:24:35.609Z","metaMigratedFrom":"YAML","title":"Docker OverView","breaks":true,"slideOptions":"{\"transition\":\"fade\",\"parallaxBackgroundImage\":\"https://s3.amazonaws.com/hakim-static/reveal-js/reveal-parallax-1.jpg\",\"parallaxBackgroundSize\":\"2100px 1100px\",\"allottedMinutes\":5}","contributors":"[{\"id\":\"3fb4bc3a-7154-4d90-b785-69b4345d269a\",\"add\":8809,\"del\":0}]"}