Docker 实践

  • Image/镜像: 系统镜像 CentOS.iso
  • Container/容器: 虚拟机 VM
  • Docker Hub: 镜像中心 GitHub

查看 container ID / Get the ID of the container by using the docker ps command.

1
docker ps

停止 container / Use the docker stop command to stop the container.

1
2
# Swap out <the-container-id> with the ID from docker ps
docker stop <the-container-id>

删除 container,-f 强删 / Once the container has stopped, you can remove it by using the docker rm command.

1
docker rm <the-container-id>

CentOS 8 新用户

root 帐号添加新用户

1
2
adduser iosdevlog
visudo

添加 iosdevlog 那一行

1
2
3
## Allow root to run any commands anywhere
root ALL=(ALL) ALL
iosdevlog ALL=(ALL) ALL

切换到 iosdevlog

1
2
su - iosdevlog
echo $USER

安装 Docker

Get Started with Docker

设置仓库

1
2
3
sudo yum install -y yum-utils \
device-mapper-persistent-data \
lvm2
1
2
3
sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo

安装 Docker Engine-Community

1
sudo yum install docker-ce docker-ce-cli containerd.io --nobest

启动 Docker

1
sudo systemctl start docker

通过运行 hello-world 映像来验证是否正确安装了 Docker Engine-Community

1
sudo docker run hello-world

非 root 用户运行

1
2
3
4
5
6
sudo cat /etc/group | grep docker
# sudo groupadd -g 999 docker
sudo gpasswd -a $USER docker # 将当前用户加入到 docker 用户组中
newgrp docker # 更新用户组
sudo systemctl restart docker # 重启 docker-daemon
docker version # 运行 docker

Docker 101 Tutorial

1
docker run -d -p 80:80 docker/getting-started

You'll notice a few flags being used. Here's some more info on them:

  • -d - run the container in detached mode (in the background)
  • -p 80:80 - map port 80 of the host to port 80 in the container
  • docker/getting-started - the image to use

查看 container

1
docker ps

remove container

1
docker rm -f <the-container-id>

dev 开发

Dockerfile

1
2
3
4
5
FROM node:12-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "/app/src/index.js"]

创建 image -t tag

1
docker build -t getting-started .

运行刚才创建的 getting-started

1
docker run -dp 3000:3000 getting-started
1
2
-                <p className="text-center">No items yet! Add one above!</p>
+ <p className="text-center">You have no todo items yet! Add one above!</p>

Docker Hub

1
2
3
docker login -u iosdevlog
docker tag getting-started iosdevlog/getting-started
docker push iosdevlog/getting-started

Play with Docker

1
docker run -dp 3000:3000 iosdevlog/getting-started

打开 3000 按钮

持久化 Persisting our Todo Data¶

1
2
docker volume create todo-db
docker run -dp 3000:3000 -v todo-db:/etc/todos iosdevlog/getting-started

数据保存位置

1
2
3
4
5
6
7
8
9
10
11
12
docker volume inspect todo-db
[
{
"CreatedAt": "2020-03-27T12:28:25Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/todo-db/_data",
"Name": "todo-db",
"Options": {},
"Scope": "local"
}
]

绑定挂载 Using Bind Mounts

  • Named Volumes Bind Mounts
    Host Location Docker chooses You control
    Mount Example (using -v) my-volume:/usr/local/data /path/to/data:/usr/local/data
    Populates new volume with container contents Yes No
    Supports Volume Drivers Yes No
1
2
3
4
docker run -dp 3000:3000 \
-w /app -v $PWD:/app \
node:12-alpine \
sh -c "yarn install && yarn run dev"

查看 logs

1
2
3
4
5
6
7
8
docker logs -f <container-id>
$ nodemon src/index.js
[nodemon] 1.19.2
[nodemon] to restart at any time, enter `rs`
[nodemon] watching dir(s): *.*
[nodemon] starting `node src/index.js`
Using sqlite database at /etc/todos/todo.db
Listening on port 3000

src/static/js/app.js

1
2
-                         {submitting ? 'Adding...' : 'Add Item'}
+ {submitting ? 'Adding...' : 'Add'}

Using bind mounts is very common for local development setups.

在本地开发设置中,使用绑定挂载很常见。

开发完成后就可以创建自己的 image

1
docker build -t getting-started .

多个容器 Multi-Container Apps

Create the network.

1
docker network create todo-app

Start a MySQL container and attach it the network.

1
2
3
4
5
6
docker run -d \
--network todo-app --network-alias mysql \
-v todo-mysql-data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=secret \
-e MYSQL_DATABASE=todos \
mysql:5.7

connect to the database

1
2
docker exec -it <mysql-container-id> mysql -p
Enter password: secret
1
2
3
4
5
6
7
8
9
10
11
mysql> SHOW DATABASES;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| todos |
+--------------------+
5 rows in set (0.05 sec)

Connecting to MySQL

1
2
3
4
5
6
7
8
9
10
docker run -it --network todo-app nicolaka/netshoot
Status: Downloaded newer image for nicolaka/netshoot:latest
dP dP dP
88 88 88
88d888b. .d8888b. d8888P .d8888b. 88d888b. .d8888b. .d8888b. d8888P
88' `88 88ooood8 88 Y8ooooo. 88' `88 88' `88 88' `88 88
88 88 88. ... 88 88 88 88 88. .88 88. .88 88
dP dP `88888P' dP `88888P' dP dP `88888P' `88888P' dP

Welcome to Netshoot! (github.com/nicolaka/netshoot)

dig

1
dig mysql

output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
; <<>> DiG 9.14.8 <<>> mysql
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 61687
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0

;; QUESTION SECTION:
;mysql. IN A

;; ANSWER SECTION:
mysql. 600 IN A 172.18.0.2

;; Query time: 7 msec
;; SERVER: 127.0.0.11#53(127.0.0.11)
;; WHEN: Fri Mar 27 16:00:31 UTC 2020
;; MSG SIZE rcvd: 44
  • MYSQL_HOST - the hostname for the running MySQL server
  • MYSQL_USER - the username to use for the connection
  • MYSQL_PASSWORD - the password to use for the connection
  • MYSQL_DB - the database to use once connected
1
2
3
4
5
6
7
8
9
docker run -dp 3000:3000 \
-w /app -v $PWD:/app \
--network todo-app \
-e MYSQL_HOST=mysql \
-e MYSQL_USER=root \
-e MYSQL_PASSWORD=secret \
-e MYSQL_DB=todos \
node:12-alpine \
sh -c "yarn install && yarn run dev"

docker logs <container-id>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
yarn install v1.22.0
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.54s.
yarn run v1.22.0
$ nodemon src/index.js
[nodemon] 1.19.2
[nodemon] to restart at any time, enter `rs`
[nodemon] watching dir(s): *.*
[nodemon] starting `node src/index.js`
Waiting for mysql:3306.
Connected!
Connected to mysql db at host mysql
Listening on port 3000

docker exec -ti <mysql-container-id> mysql -p todos

1
2
3
4
5
6
7
8
mysql>  select * from todo_items;
+--------------------------------------+---------------------------------------+-----------+
| id | name | completed |
+--------------------------------------+---------------------------------------+-----------+
| 9b3dc86c-2ec9-4413-8a71-28b3c3515358 | DevOps | 0 |
| 9428c285-e5e1-4f50-bf11-ee854cc8554f | Hello, I'm AIDevLog. Welcome to 2020! | 0 |
+--------------------------------------+---------------------------------------+-----------+
2 rows in set (0.00 sec)

docker-compose

https://docs.docker.com/compose/install/

Compose 使用的三个步骤:

  1. 使用 Dockerfile 定义应用程序的环境。
  2. 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
  3. 最后,执行 docker-compose up 命令来启动并运行整个应用程序。
1
2
3
sudo curl -L "https://github.com/docker/compose/releases/download/1.25.4/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
docker-compose --version

output

docker-compose version 1.25.4, build 8d51620a

Creating our Compose File

1
2
# pwd: app
cat docker-compose.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
version: "3.7"

services:
app:
image: node:12-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
working_dir: /app
volumes:
- ./:/app
environment:
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: secret
MYSQL_DB: todos

Running our Application Stack

1
docker rm -f <container-id>

docker-compose up

1
docker-compose up -d

output

Creating network "app_default" with the default driver

Creating volume "app_todo-mysql-data" with default driver

Creating app_mysql_1 ... done

Creating app_app_1 ... done

log

1
docker-compose logs -f

output

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Attaching to app_mysql_1, app_app_1
app_1 | yarn install v1.22.0
app_1 | [1/4] Resolving packages...
...
app_1 | Waiting for mysql:3306...............
app_1 | Connected!
app_1 | Connected to mysql db at host mysql
app_1 | Listening on port 3000
mysql_1 | 2020-03-27 16:37:47+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.29-1debian10 started.
...
mysql_1 | 2020-03-27T16:38:06.309134Z 0 [Note] Event Scheduler: Loaded 0 events
mysql_1 | 2020-03-27T16:38:06.309309Z 0 [Note] mysqld: ready for connections.
mysql_1 | Version: '5.7.29' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL)
mysql_1 | 2020-03-27T16:38:06.365195Z 2 [Note] Got an error reading communication packets

Tearing it All Down

1
docker-compose down

Image Building Best Practices

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ docker image history getting-started
IMAGE CREATED CREATED BY SIZE COMMENT
7e58c32dc1b5 5 hours ago /bin/sh -c #(nop) CMD ["node" "/app/src/ind… 0B
ebe4a0dcca7e 5 hours ago /bin/sh -c yarn install --production 83.2MB
3fd0eef12d70 5 hours ago /bin/sh -c #(nop) COPY dir:2f31be1c05e031e42… 6.65MB
c164b9c205a1 5 hours ago /bin/sh -c #(nop) WORKDIR /app 0B
f77abbe89ac1 3 days ago /bin/sh -c #(nop) CMD ["node"] 0B
<missing> 3 days ago /bin/sh -c #(nop) ENTRYPOINT ["docker-entry… 0B
<missing> 3 days ago /bin/sh -c #(nop) COPY file:238737301d473041… 116B
<missing> 3 days ago /bin/sh -c apk add --no-cache --virtual .bui… 7.62MB
<missing> 3 days ago /bin/sh -c #(nop) ENV YARN_VERSION=1.22.0 0B
<missing> 3 days ago /bin/sh -c addgroup -g 1000 node && addu… 74.9MB
<missing> 3 days ago /bin/sh -c #(nop) ENV NODE_VERSION=12.16.1 0B
<missing> 3 days ago /bin/sh -c #(nop) CMD ["/bin/sh"] 0B
<missing> 3 days ago /bin/sh -c #(nop) ADD file:0c4555f363c2672e3… 5.6MB

Layer Caching¶

Update the Dockerfile to copy in the package.json

1
2
3
4
5
6
FROM node:12-alpine
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --production
COPY . .
CMD ["node", "/app/src/index.js"]

Build a new image using docker build

1
docker build -t getting-started .

更改 src/static/index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
diff --git a/src/static/index.html b/src/static/index.html
index a606bf1..19cfb57 100644
--- a/src/static/index.html
+++ b/src/static/index.html
@@ -8,7 +8,7 @@
<link rel="stylesheet" href="css/font-awesome/all.min.css" crossorigin="anonymous" />
<link href="https://fonts.googleapis.com/css?family=Lato&display=swap" rel="stylesheet" />
<link rel="stylesheet" href="css/styles.css" />
- <title>Todo App</title>
+ <title>AIDevLog Todo App</title>
</head>
<body>
<div id="root"></div>

docker build

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ docker build -t getting-started .
Sending build context to Docker daemon 65.73MB
Step 1/6 : FROM node:12-alpine
---> f77abbe89ac1
Step 2/6 : WORKDIR /app
---> Using cache
---> c164b9c205a1
Step 3/6 : COPY package.json yarn.lock ./
---> Using cache
---> 77446d8145bc
Step 4/6 : RUN yarn install --production
---> Using cache
---> f0323073e6ce
Step 5/6 : COPY . .
---> 0e1288f88991
Step 6/6 : CMD ["node", "/app/src/index.js"]
---> Running in f3a0bd941311
Removing intermediate container f3a0bd941311
---> 2abff2421550
Successfully built 2abff2421550
Successfully tagged getting-started:latest

Docker-Cheatsheets.md

Clean all

1
2
3
4
docker stop `docker ps -a -q` 
docker rm `docker ps -a -q`
docker rmi -f `sudo docker images -q`
docker volume rm $(docker volume ls -f dangling=true -q)

Clean image

1
docker images --no-trunc | grep none | awk '{print $3}' | xargs docker rmi -f

Change docker image location

1
2
btrfs subvolume create /mnt/disk/@docker
rsync -aqxP /var/lib/docker/* /mnt/disk/@docker
  • method 1: 變更 docker 儲存路徑
1
sudo vi /etc/docker/daemon.json
1
2
3
4
5
6
7
{
"registry-mirrors":["https://cache-docker.hopebaytech.com"],
"insecure-registries":["docker:5000"],
"dns":["172.16.1.254", "8.8.8.8"],
"graph": "/mnt/disk/docker",
"storage-driver": "btrfs"
}

重新啟動服務

1
2
3
sudo systemctl stop docker
sudo systemctl daemon-reload
sudo systemctl start docker

啟動設定檔位置

1
2
3
/etc/docker/daemon.json
/etc/default/docker
/etc/systemd/system/docker.service.d/docker.conf

Attach a running container

1
2
3
4
5
6
7
8
# list containers
docker ps -a

# attach a running containers
docker attach [CONTAINER ID]

# attach a running containers into bash
docker exec -i -t arkease-pro-web bash