docker 使用入门
在公司使用微服务之后,因为各个服务之间有依赖关系,调试自己服务的时候每次都需要编译运行其他服务,原来使用一台开发机作为开发环境的方式就很麻烦,所以考虑用 docker
部署一套可以复用的开发环境。首先了解下docker
的基本使用。
安装
点击链接下载 docker-desktop ,然后傻瓜式安装。
安装好之后可以在命令行执行 docker --version
命令,查看 docker
是否正常运行。
教程
官方肯定有教程的,所以可以去官网找一下,我这边看的是 docker/getting-started
的教程。docker/getting-started
本身就是一个 docker
的 repo
。下面说一下怎么看这个教程。
在安装好 docker
之后,在命令行运行 docker run -d -p 80:80 docker/getting-started
命令, 然后就启动了一个容器。
然后本地浏览器访问 http://localhost/tutorial/
可以看到教程。英文的,但是很好理解,有点英语基础都可以看懂。本篇教程也是按照这个教程来的,记录下方便以后自己用。
接下来只讲使用,不讲原理。
使用
创建第一个自己的APP
教程提供了一个 Node.js
的应用让我们直接使用,点击下载 Node.js APP , 本地的连接,上述步骤没做下载不下来。
将下载的 zip 文件解压,用编辑器打开, 这边我用的是 vscode
。
创建该APP镜像
在下载的APP
的跟目录下创建一个名称为
Dockerfile
的文件,文件内容如下:
FROM node:12-alpine
RUN apk add --no-cache python g++ make
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
在
APP
跟目录下运行如下命令:
docker build -t getting-started .
-t
是给镜像取个名字,名字是 getting-started
。 最后的 .
代表的是运行的是当前目录下的 Dockerfile
文件。
启动一个APP容器
使用docker run
命令启动一个容器,启动的时候要指定使用刚才构建的镜像。命令如下:
docker run -dp 3000:3000 getting-started
启动之后,在本地浏览器输入 http://localhost:3000 。可以看到一个
todo list
应用。 你可以在应用中使用一下。如果是自己的应用基本就可以使用了。
你现在可以看下下载的 docker-desktop
面板,里面有两个容器,一个是用来看教程的,一个是新创建的自己的 APP
。
更新APP容器
启动容器后,容器内的应用代码肯定不是一成不变的,加个需求不是很正常的事情嘛,所以需要在更改代码之后,重新构建镜像,用新镜像重新启动容器。
修改代码,在src/static/js/app.js
文件下更新第 56 行
- <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 build -t getting-started .
删除原有容器,不删除原有容器直接启动会因为
3000
端口占用启不起来。可以用命令删除,或者直接在
docker-desktop
面板上直接删除。下面介绍下命令删除。 首先用命令
docker ps
找到所有启动的容器。如下图:
图中第一列就是容器id,然后还用
docker rm <the-container-id>
命令删除该容器。 根据新镜像重新启动容器,命令如下。
docker run -dp 3000:3000 getting-started
重新看下应用 http://localhost:3000 。
持久化数据库
docker
中每个容器的文件系统都是独立的,一个容器无法访问到另一个容器的文件。同一个容器,再重启后旧容器中的文件就丢了。所以上面的 todo list APP
再容器更新后之前加的 todo
就没了。那怎么让容器更新后还能访问到之前的数据呢?
这里引出容器的 volumes
概念。 volumes
会将容器内的目录映射到宿主机的目录上,然后每次启动的时候都加载宿主机的目录,文件就不会丢了。
有两种类型的 volumes
,一种是 named volumes , 另一种是 bind mounts 。
named volumes
首先讲一下 named volumes :
使用docker volume create
命令创建一个 volume 。
docker volume create todo-db
删除已经存在的
todo list APP
容器。步骤上面已经说了。 用
docker run
命令重新启动容器,这次启动要加
-v
参数,命令如下:
docker run -dp 3000:3000 -v todo-db:/etc/todos getting-started
-v
就是指定 volumes
的意思。
todo
。 然后删除
APP
容器,重新启动一个。 再次刷新应用,确认刚才的几条
todo
没有丢。
注:查看
Valumes
信息命令:docker volume inspect <valumes name>
bind mounts
然后再来说一下 bind mounts ,它会将宿主机内的目录与容器内的目录绑定,然后改变宿主机目录下的内容,容器内的也会改变,这就可以实现在宿主机改代码,及时同步到容器内。使用流程:
关闭所有的getting-started
容器。 运行以下命令:
docker run -dp 3000:3000 \
-w /app -v "$(pwd):/app" \
node:12-alpine \
sh -c "yarn install && yarn run dev"
如果是 PowerShell ,运行如下命令:
docker run -dp 3000:3000 `
-w /app -v "$(pwd):/app" `
node:12-alpine `
sh -c "yarn install && yarn run dev"
命令解释如下:
-dp
:是参数
-d
,
-p
的缩写,
-d
代表后台运行,
-p
指定端口。
-w /app
:容器内工作目录,程序运行的目录。
-v "$(pwd):/app"
: 这里指定了
volumes
, 将宿主机的当前目录与容器的
/app
目录绑定。
node:12-alpine
:使用的镜像
sh -c "yarn install && yarn run dev"
:运行 shell 用命令
docker logs -f <container-id>
查看日志,如果你看到以下内容代表启动成功:
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
文件的 109 行 "Add Item" 改成 "Add":
- {submitting ? 'Adding...' : 'Add Item'}
+ {submitting ? 'Adding...' : 'Add'}
刷新网页看效果。
创建一个多容器的 APP
该 todo list APP
之前用的是 SQLite Database 来作为存储的。现在使用个更通用的,比如 MYSQL
。 当然可以直接把 MYSQL
跟 APP
部署到同一台机器上,但是 docker
不建议这么做。 docker
希望每个容器内的功能单一。所以现在的部署方案是两个容器,一个部署 MYSQL
,一个部署 APP
。 像这样:
这样两个容器之间需要通过网络连接。这样就引出 network 概念。同一个 network 上的容器可以相互通信。
创建启动MYSQL容器
创建一个 network :docker network create todo-app
启动一个
MYSQL 容器,将该容器连接到上一步创建的
network 上面。
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
如果用的 PowerShell
:
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
这里用到了 --network-alias
, 该属性的意思是: 其他容器连接 mysql
填写 host
的时候,直接填 --network-alias
的值 mysql
就行。相当于域名。
mysql
容器是否正常运行
docker exec -it <mysql-container-id> mysql -p
连接到mysql
之后运行:
mysql> SHOW DATABASES;
可以看到 todos
库:
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| todos |
+--------------------+
5 rows in set (0.00 sec)
启动 APP 容器连接到 MYSQL
关闭所有的getting-started
容器。 重新启动容器
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"
如果是PowerShell :
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"
新增了 --network todo-app
来连接到 todo-app
网络,确保跟 mysql
一个网络就好。
同时新增了几个 -e
参数,代表指定要连接的mysql
的环境变量。
docker logs <container-id>
, 会看到如下内容:
# Previous log messages omitted
$ 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`
Connected to mysql db at host mysql
Listening on port 3000
打开网页 http://localhost:3000 新加几个
todo
。 运行命令连接到
mysql
:
docker exec -it <mysql-container-id> mysql -p todos
运行如下命令查看是否有新增的数据:
mysql> select * from todo_items;
Docker compose
启动了 todo list
和 mysql
之后,在 docker-desktop
面板上看到的是两个容器,但是两个容器是有联系的,会同时启动和关闭,那该怎么让两个容器联动起来呢?
这里就要用到 docker compose
,通过一个 YAML
文件,可以同时启动和关闭两个容器,或者叫一组相关容器。
docker-compose.yml
文件,跟最开始的
Dockerfile
同一目录下。 文件内容如下:
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
mysql:
image: mysql:5.7
volumes:
- todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: secret
MYSQL_DATABASE: todos
volumes:
todo-mysql-data:
删除刚才创建的
getting-started
和
mysql
两个容器。 在项目根目录下运行如下命令启动这组容器:
docker-compose up -d
运行的时候回看到如下输出:
Creating network "app_default" with the default driver
Creating volume "app_todo-mysql-data" with default driver
Creating app_app_1 ... done
Creating app_mysql_1 ... done
注意到 volume
和 network
都创建了,即使 network
没有指定。这是因为默认情况下,compose
会创建一个公共的 network
。
docker-compose logs -f
命令看下日志。 刷新下浏览器,现在可以正常使用了。然后可以观察下
docker-desktop
面板,可以看到两个容器放在了一起。 然后可以通过
docker-compose down
命令或者直接在面板上点击关闭这组容器。
总结
因为要搭建环境,将 docker
官网的内容整理简化,记录出来。