---
# System prepended metadata

title: docker
tags: [docker]

---

---
title: docker
tags: docker
---

[toc]

# Docker vs VM

![docker ](https://i.imgur.com/2CFPuDY.png)

| 特性      | 說明 |
| -------- | -------- |
| 靈活性    | 複雜的應用程式也可以容器化        |
| 輕量化	 | 容器共享內核，系統消耗比虛擬機器低 | 
| 可移植	 | 可在本地建構，部署到任何地方運行   | 
| 低耦合	 | 容器間相依低，更換或者升級不會影響其他容器  | 
| 可擴展	 | 可以在數據中心跑多個容器  | 
| 安全性	 | 容器之間預設的網路是隔離的  | 

| 特性       | Docker         | VM        |
| --------  | --------       | ---       |
| 啟動速度	  | 秒級	         | 分鐘級     | 
| 硬碟使用	  | 一般為MB       | 一般為GB   | 
| 性能	   | 接近原生        | 	較差      | 
| 系統支援量  | 單機支持上千容器	 | 一般幾十個 | 
| 隔離性     | 安全隔離	     | 完全隔離   | 

# 基本概念

* Image 映像檔
  * Image是一個模板，用來產生容器
  * Image包含完整的服務、編譯環境、或是作業系統

* Container 容器
  * 容器是用映像檔建立出來的實體
  * 它可以被啟動、開始、停止、刪除
  * 每個容器都是相互隔離。

* Repository 倉庫
  * 倉庫是映像檔存放的地方
  * 倉庫可分為公開倉庫和私有倉庫
  * Docker Hub是官方公開倉庫，存放了許多官方維護的映像檔供使用者下載

# install
```bash=
winget install -e --id Docker.DockerDesktop

brew install --cask docker

sudo apt-get install docker.io

```
# docker命令

![docker commands diagram](https://i.imgur.com/BssPo3z.png)

```bash=
docker info
docker version

docker images
docker rmi $(docker images -f dangling=true -qa)
docker rmi $(docker images -qa)

# 以nginx為例
docker pull nginx:1.21.6-alpine

# 生命週期
watch docker ps -a
docker run -d --name w1 -p 8080:80 -v /tmp/html:/usr/share/nginx/html nginx:1.21.6-alpine
docker logs -f w1
docker stop w1
docker start w1
docker restart w1
docker pause w1
docker unpause w1
docker kill w1
docker rm w1

# 匯出匯入
watch docker images
docker run -i -t --rm --name w2 -p 8080:80 nginx:1.21.6-alpine
docker exec -i -t w2 sh
docker commit -m 'edit index' w2

docker cp w2:/usr/share/nginx/html/index.html .
docker cp ./index.html w2:/usr/share/nginx/html

docker export w2 > w2.tar
docker import ./w2.tar abc123:0.0.1

docker save abc123:0.0.1 > abc123.tar
docker rmi abc123:0.0.1
docker load < abc123.tar

docker stop w2
docker rmi nginx:1.21.6-alpine
docker tag abc123:0.0.1 nginx:1.21.6-alpine

```

# Dockerfile
![docker build and run](https://i.imgur.com/ZXgmvzp.png)

```yaml=
# 基底映像檔
FROM ubuntu:20.04 as base

# 影像檔資訊
# LABEL maintainer="abc@example.com"
# LABEL description='abc123'

# 指定執行容器的user
USER node

# 容器編譯時期執行的命令
RUN apt-get update \
    && apt-get upgrade -y \

# 工作目錄
WORKDIR /app

# 容器執行時期的環境變數
ENV TYPEORM_HOST=127.0.0.1
ENV TYPEORM_USERNAME=usr
ENV TYPEORM_DATABASE=pwd

# 編譯時用 --build-arg 帶入的參數
# 容器編譯時期的變數
# ARG 

# 複製本機的資料至容器內
COPY dist /app/dist

# 複製網路的資料，並自動解壓縮到容器內
# ADD https://www.example.com/abc.tar /app/lib/

# 建立一個可以對外掛載的目錄
# VOLUME 

# 宣告此容器Listen的Port號
EXPOSE 3000

# 指定容器啟動程序及參數
# ENTRYPOINT ["entrypoint.sh"]

# 容器啟動時執行的命令
CMD ["node", "dist/main"]
```

```bash=
docker build -t abc:123 .
docker build -t abc:456 -f dev.dockerfile .
docker tag abc:123 xyz:456
```

```bash=
FROM busybox
ENTRYPOINT ["ping"]
CMD ["168.95.1.1"]
```

# Understand how CMD and ENTRYPOINT interact
[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-alpine as base
RUN mkdir -p /app && chown -R node:node /app
USER node
WORKDIR /app

ENV NODE_ENV production

COPY --chown=node:node dist /app/dist
COPY --chown=node:node .npmrc package.json /app/
RUN npm install

EXPOSE 3000
CMD ["node", "dist/main"]
```

# docker compose
```yaml=
version: '3.5'

networks:
  local:
    name: local

services:
  db:
    container_name: 'mysql'
    image: 'mysql:8.0.29'
    command: ['--character-set-server=utf8mb4', '--collation-server=utf8mb4_unicode_ci']
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: db01
      MYSQL_USER: dev
      MYSQL_PASSWORD: dev
    ports:
      - 3306:3306
    networks:
      - local

  adminer:
    container_name: 'adminer'
    image: 'adminer:4.8.1'
    restart: always
    ports:
      - 8080:8080
    networks:
      - local

```
```bash=
docker-compose up
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
```

# Makefile
```
DIRNAME:= $(notdir $(CURDIR))

.PHONY: build

build:
	docker build -t $(DIRNAME):local .

run:
	docker run -i -t --rm -p 3000:3000 $(DIRNAME):local

rmi:
	docker rmi $(DIRNAME):local

clean:
	rm -rf coverage
	rm -rf node_modules
	rm -rf dist
	rm -f junit.xml
	rm -f package-lock.json

```
# Container Registry
[CNCF Container Registry](https://landscape.cncf.io/card-mode?category=container-registry&grouping=category)

* Harbor
* Portus
* Nexus Repository 
* Docker Hub
* Google Container Registry
* Azuer Container Registry
* Amazon Elastic Container Registry
