Files
rikako-note/docker/docker guide.md

236 lines
9.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

- [docker guide](#docker-guide)
- [Push image to docker hub](#push-image-to-docker-hub)
- [volume mount](#volume-mount)
- [volume detail](#volume-detail)
- [bind mount](#bind-mount)
- [bind mount和volume mount区别](#bind-mount和volume-mount区别)
- [docker run -v](#docker-run--v)
- [multi container app](#multi-container-app)
- [container networking](#container-networking)
- [create network](#create-network)
- [nicolaka/netshoot](#nicolakanetshoot)
# docker guide
## Push image to docker hub
1. 通过命令`docker login -u ${username}`登录docker hub
2. 使用`docker tag`命令给镜像`getting-started`一个新的名称。需要用docker hub id替换`YOUR-USER-NAME`
```shell
$ docker tag getting-started YOUR-USER-NAME/getting-started
```
3. 如果`git push`操作未指定tagname那么默认会使用tag `latest`
```shell
$ docker push YOUR-USER-NAME/getting-started
```
## volume mount
在一个容器中对文件进行的操作(修改、删除、新增)在容器被删除后都会丢失,即使两个容器从同一镜像启动,一个容器的修改对另一个容器仍然不可见。
`volume`提供了将容器中文件系统指定路径连接到宿主机的功能。在容器中被挂载的目录下,对文件的修改也会同步到宿主机的路径下。如果在不同的容器启动时挂载相同的目录,那么目录下的文件将会在容器之间进行共享。
volume可以看作是一个不透明的数据桶volume完全由docker管理docker会管理volume在磁盘中存储的位置。用户只需要指定volume的name即可。
1. 创建docker volume
```shell
docker volume create todo-db
```
2. 通过`--mount`选项将volume挂载到容器中。使用示例如下所示
```shell
<!--
src指定volume的name
target指定挂载路径
-->
# docker run -dp 3000:3000 --mount type=volume,src=todo-db,target=/etc/todos getting-started
```
### volume detail
如果想要知道volume的详细信息例如在宿主机中的存储位置可以调用`docker volume inspect`命令:
```shell
$ docker volume inspect todo-db
[
{
"CreatedAt": "2019-09-26T02:18:36Z",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/todo-db/_data",
"Name": "todo-db",
"Options": {},
"Scope": "local"
}
]
```
## bind mount
相对于volume mountbind mount能够让同一目录在宿主机和容器之间进行共享宿主机对于路径下文件的修改能对容器可见。
1. 执行如下命令创建bind mount将宿主机路径挂载到容器中
```shell
<!--
当mount type为bind时
src为宿主机路径
target为容器的目标路径
-->
docker run -it --mount type=bind,src="$(pwd)",target=/src ubuntu bash
```
### bind mount和volume mount区别
对于bind mount不管宿主机中是否由内容宿主机路径对应的文件内容都会覆盖容器目录中的内容。
对于volume mount如果volume中没有内容会将容器目录下的内容复制到宿主机的volume中如果volume中有内容volume中内容会覆盖容器目录中的内容。
### docker run -v
`docker run -v`命令后由三部分组成,形式为`src:dest:mode`当src为宿主机的一个路径时使用的是bind mount如果src为一个name时使用的是volume mount。第三块是可选的为读写权限默认情况下mode为rw。
## multi container app
通常情况下每个容器之应该做一件事情。故而例如一个应用需要mysql应该将mysql置于另一个容器中进行部署。
### container networking
容器在默认情况下是隔离运行的,不知道位于同一机器上的其他容器和进程。故而,容器之间通过网络进行通信。
如果多个容器需要通过network进行通信那么需要将多个容器放置到同一个network中。
### create network
可以通过如下命令创建一个网络:
```shell
$ docker network create todo-app
```
如下命令会启动一个mysql容器并且将其添加到todo-app的网络中
```shell
$ 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:8.0
```
`--network todo-app`选项会将mysql容器添加到`todo-app`网络中,而`--network-alias mysql`则会创建一条dns `mysql`该条dns指向mysql容器的ip地址。
> 在上述指令中,并没有调用`docker volume create`命令来创建volumedocker知道我们要使用命名好的volume并会为我们自动创建。
### nicolaka/netshoot
nicolaka/netshoot容器中集成了很多网络工具在解决网络问题时会很有用。
1. 将netshoot容器添加到指定网络中
```shell
$ docker run -it --network todo-app nicolaka/netshoot
```
2. 在netshoot容器中使用dig命令dig是很有用的DNS工具
```shell
$ dig mysql
```
dig命令输出如下
```shell
; <<>> DiG 9.18.8 <<>> mysql
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 32162
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0
;; QUESTION SECTION:
;mysql. IN A
;; ANSWER SECTION:
mysql. 600 IN A 172.23.0.2
;; Query time: 0 msec
;; SERVER: 127.0.0.11#53(127.0.0.11)
;; WHEN: Tue Oct 01 23:47:24 UTC 2019
;; MSG SIZE rcvd: 44
```
其中ANSWER SECTION输出了network-alias mysql对应的ip地址。
> mysql并不是一个有效的域名但是docker能将该network-alias解析为对应容器的ip地址
## docker compose
docker compose是用于定义和共享多容器应用的工具。通过compose可以通过一个yaml文件来定义应用服务并且通过单行命令启动和停止多容器应用服务。
### 创建compose file
1. 定义container的service条目和对应image我们可以为service指定任何名称。该指定的名称会自动成为network-alias
```yml
services:
app:
image: node:18-alpine
```
2. 在为service定义name和image之后可以为service指定command
```yml
services:
app:
image: node:18-alpine
command: sh -c "yarn install && yarn run dev"
```
3. 为service指定ports
```yml
services:
app:
image: node:18-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
```
4. 为service设置workdir或挂载卷时通过如下方式进行
```yml
services:
app:
image: node:18-alpine
command: sh -c "yarn install && yarn run dev"
ports:
- 3000:3000
working_dir: /app
volumes:
- ./:/app
```
5. 如果需要为service指定环境变量如果如下方式进行配置
```yml
services:
app:
image: node:18-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
```
6. 在docker run时通过-v选项指定的volume name不存在那么volume会自动被创建但是在compose file中通过volumes指定的volume name并不会被自动创建。想要创建volume必须yml文件的顶层`volumes:`中指定volume 。
通常情况下,只用指定`volume-name:`即可,会使用默认的选项。
示例如下所示:
```yml
services:
app:
# The app service definition
mysql:
image: mysql:8.0
volumes:
- todo-mysql-data:/var/lib/mysql
volumes:
todo-mysql-data:
```
7. 最终整合两个docker container的应用yml文件配置如下所示
```yml
services:
app:
image: node:18-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
mysql:
image: mysql:8.0
volumes:
- todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: todos
volumes:
todo-mysql-data:
```
### run application stack
可以通过`docker compose up`命令来启动application stack。可以通过添加-d选项在后台运行
```shell
docker compose up -d
```
**默认情况下docker compose会自动为compose文件中的application stack创建一个network。**
如果想要停止application stack可以调用`docker compose down`命令。
> 默认情况下docker compose down并不会移除创建的volume如果想要移除volume可以指定选项--volumes