博文目录
文章目录
- 新手向导 (Get Started)
- 应用程序容器化
- 下载应用代码
- 容器化该应用
- 配置镜像加速器
- 启动这个应用容器
- 更新应用程序
- 共享应用程序
- 推送镜像
- Play with Docker
- 使用镜像
- 持久化数据库
- 容器的文件系统
- 容器卷 (Container volumes)
- 保留所有数据
- 深入卷
- 使用绑定装载
- 快速卷类型比较
- 尝试绑定装载
- 开发容器
- 在开发容器中运行应用程序
- 使用开发容器开发应用程序
- 多容器应用程序
- 容器网络
- 启动 MySQL
- 连接到 MySQL
- 使用 MySQL 运行应用程序
- 使用 Docker Compose
- 安装 Docker Compose
- 常用命令
- 帮助命令
- 镜像命令
- docker images
- docker search
- docker pull
- docker rmi
- 容器命令
- docker run 创建容器
- docker ps 列出容器
- docker rm 删除容器
- 启动和停止容器
- 其他常用命令
- 后台启动
- docker logs 查看日志
- docker top 查看容器中的进程信息
- docker inspect 查看容器的元数据
- 进入当前运行的容器
docker入门,这一篇就够了。
新手向导 (Get Started)
官方文档 Get Started
本向导中的试验部分需要一台Linux主机, 可以是云服务器, 也可以是虚拟机, 需安装 Docker 环境
应用程序容器化
本节里, 我们会容器化一个简单的 Web Node.js 应用 Todo
, 它的主要功能就是管理一些要做的事项, 可以添加/删除事项, 可以标记事项已完成. 这个示例并不需要我们熟悉 Node.js 和 JavaScript, 仅仅是展示下构建镜像运行镜像的流程
下载应用代码
如果Linux服务器上安装了Git, 那可以直接运行 git clone https://github.com/docker/getting-started.git
克隆项目代码, 也可以在Windows上克隆代码, 再通过FTP工具传到服务器
容器化该应用
要构建镜像, 需要使用 Dockerfile
, 这是一个文本文件, 没有扩展名
通过 cd getting-started/app
进入 app 目录, 目录中有 package.json 和 spec 与 src 两个目录, 通过 touch Dockerfile
新建一个 Dockerfile, 使用 vim 或 文本编辑器 把下面的内容写入到 Dockerfile 中
# syntax=docker/dockerfile:1
FROM node:18-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "src/index.js"]
EXPOSE 3000
然后通过 docker build -t getting-started .
命令构建镜像
docker build 命令使用Dockerfile来构建一个新的镜像。你可能已经注意到Docker下载了很多“层”。这是因为您指示生成器要从 node:18-alpine 节点开始。但是,由于你的机器上没有,Docker会自动下载这些镜像。
Docker下载镜像后,Dockerfile中的指令会复制到您的应用程序中,并使用yarn安装应用程序的依赖项。CMD指令指定从此映像启动容器时要运行的默认命令。
最后,-t 选项用于标记您的镜像。可以简单地认为是指定最终镜像的名称。由于您在开始时命名了该镜像,因此在运行容器时可以引用该镜像。
这个 `.` 在docker构建命令的末尾,告诉docker它应该在当前目录中查找Dockerfile。
构建成功后, 执行 docker images
即可看到该镜像
REPOSITORY TAG IMAGE ID CREATED SIZE
getting-started latest ed1ef9e8de78 About a minute ago 265MB
配置镜像加速器
运行构建命令很有可能会失败, 大概率是网络问题, 可以配置一下国内的镜像加速器, 建议多配几家, 我一开始只配了个阿里的, 结果构建直报错, 后来又加了腾讯的和其他的, 这才最终成功, 但中途也失败了几次, 所以, 构建失败可以多执行几次, 有概率成功
阿里云 Docker 镜像加速器
当你下载安装的 Docker 版本不低于1.10时,建议直接通过daemon config进行配置。使用配置文件 /etc/docker/daemon.json
(没有时新建该文件),然后通过 systemctl restart docker
重启 Docker 即可
{
"registry-mirrors": ["https://whvuvvy4.mirror.aliyuncs.com"]
}
启动这个应用容器
镜像已经构建好了, 通过 docker run -dp 3000:3000 --name getting-started getting-started:1.0.0
命令来创建并启动该镜像的一个容器, -d
是指定容器在后台运行, -p
用来绑定服务器端口和容器内端口的映射关系, 如果没有绑定这个端口印射, 我们没有办法访问容器内的应用程序
执行 docker ps
就可以看到正在运行的容器了
在浏览器打开 http://localhost:3000
就可以看到我们的 “Todo” 应用了
更新应用程序
本节我们修改一些应用的代码, 然后将其重新构建为镜像, 并重新运行容器
修改 src/static/js/app.js
中第56行的 No items yet! Add one above!
为 You have no todo items yet! Add one above!
使用 docker build -t getting-started
命令来重新构建该镜像的新版本
REPOSITORY TAG IMAGE ID CREATED SIZE
getting-started latest b5a67802db59 About a minute ago 265MB
<none> <none> ed1ef9e8de78 15 minutes ago 265MB
使用 docker run -dp 3000:3000 --name getting-started getting-started:1.1.0
来启动新容器, 结果会报错, 新容器无法启动, 因为旧容器运行时占用了主机的3000端口, 只有停止旧容器才可以运行新容器
可以使用 docker ps
查看容器 ID, 使用 docker stop <the-container-id>
停止容器, 使用 docker rm <the-container-id>
删除容器, 也可以使用 docker rm -f <the-container-id>
直接停止并删除容器
再次使用 docker run -dp 3000:3000 --name getting-started getting-started:1.1.0
来启动新容器, 刷新浏览器可以看到文本内容已经变化
共享应用程序
要想共享镜像, 需要使用到镜像仓库, 默认的全球仓库是 Docker Hub
注册并登录 Docker Hub, 创建一个仓库, 名称使用 getting-started
, 可见性选 Public
, 我的该仓库推送镜像的命令是 docker push mrathena/getting-started:tagname
, 其中 mrathena
是 Namespace, 也就是我的账号 ID, getting-started 是仓库名称, 一个仓库只能存同名镜像的不同版本
推送镜像
执行 docker push mrathena/getting-started
报本地不存在 Tag 为 mrathena/getting-started 的镜像, 我们得 tag
本地已有的镜像并为其命名
执行 docker login -u mrathena
在命令行里登录 Docker Hub
通过执行 docker tag getting-started mrathena/getting-started
, 给 getting-started
镜像一个新的名字 mrathena/getting-started
, 如果新名称后面不追加 :tagname
部分, 则默认是 latest
REPOSITORY TAG IMAGE ID CREATED SIZE
getting-started latest b5a67802db59 15 minutes ago 265MB
mrathena/getting-started latest b5a67802db59 15 minutes ago 265MB
<none> <none> ed1ef9e8de78 29 minutes ago 265MB
再次推送, 发现推送成功了
Play with Docker
我们在自己的主机上推送镜像, 速度慢的简直无法忍受, Docker 提供了一个免费的工具 Play with Docker , 我们可以使用该工具来做我们主机能做的所有事情, 该工具连接着真正的互联网, 网速非常快, 体验相当不错
使用镜像
在另一台装有 Docker 环境的主机上, 即可下载并启动刚刚推送的镜像, 使用 Play with Docker 来完成这个测试
浏览器打开 Play with Docker, 关联到我们的 Docker Hub 账户, 点击 Start
, 再点击 ADD NEW INSTANCE
, 开始使用真正的 Docker 环境
执行 docker run -dp 0.0.0.0:3000:3000 mrathena/getting-started
即可自动下载并运行一个新的容器
持久化数据库
前面的例子里, 当我们重启容器后, 先前添加的项目就全丢失了, 本节我们将深入了解容器是如何工作的
容器的文件系统
当容器运行时,它使用镜像中的各个层作为其文件系统。每个容器也有自己的“暂存空间”来创建/更新/删除文件。即使使用的是相同的镜像,在另一个容器中也看不到当前容器中的任何更改。
容器卷 (Container volumes)
卷提供了将容器的特定文件系统路径连接回主机的能力。就是把主机的某个路径印射了到容器中的某个路径, 在容器或主机中操作文件等同于在另一方操作文件。如果在容器重新启动时装载相同的目录,则会看到相同的文件。
保留所有数据
默认情况下,Todo 应用程序将其数据存储在容器文件系统中 /etc/todos/todo.db 的 SQLite 数据库中。我们只要创建一个卷将 /etc/todos 目录印射到主机的某个目录, 其内的 todo.db 就可以保存在主机的文件系统中, 这样重启容器数据也不会丢失
我们应该将卷装载视为不透明的数据桶。由Docker完全管理卷,包括磁盘上的存储位置。我们只需要记住卷的名称。
执行 docker volume create todo-db
创建了一个卷, 执行 docker rm -f <id>
删除正在运行的容器, 执行 docker run -dp 3000:3000 --mount type=volume,src=todo-db,target=/etc/todos getting-started
启动 Todo 应用程序容器,添加 --mount
选项以指定卷装载。为卷指定一个名称,并将其装载到容器中的 ‘/etc/todos’,该容器将捕获在该路径上创建的所有文件。
执行 docker rm -f <id>
删除当前容器, 执行 docker run -dp 3000:3000 --mount type=volume,src=todo-db,target=/etc/todos getting-started
创建并启动一个新的容器, 刷新浏览器, 之前添加的数据项应该没有丢失
深入卷
执行 docker volume inspect todo-db
即可查看卷的详细信息
[
{
"CreatedAt": "2023-06-19T14:19:01+08:00",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/todo-db/_data",
"Name": "todo-db",
"Options": null,
"Scope": "local"
}
]
也可以通过 docker inspect <id>
来查看容器信息, 其中 Mounts
不分就是装载的卷的信息
"Mounts": [
{
"Type": "volume",
"Name": "todo-db",
"Source": "/var/lib/docker/volumes/todo-db/_data",
"Destination": "/etc/todos",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
],
使用绑定装载
在上节中, 我们使用了卷装载来将数据持久化到数据库中。当您需要一个持久的地方来存储应用程序数据时,卷装载是一个不错的选择。
绑定装载是另一种类型的装载,它允许您将主机文件系统中的目录共享到容器中。在处理应用程序时,可以使用绑定装载将源代码装载到容器中。保存文件后,容器会立即看到您对代码所做的更改。这意味着您可以在容器中运行进程来监视文件系统更改并对其作出响应。(感觉类似CI/CD的提交代码自动部署功能)
在本节中, 我们将使用绑定装载和名为nodemon的工具来监视文件更改,然后自动重新启动应用程序
快速卷类型比较
下表概述了卷装载和绑定装载之间的主要区别。除了卷装载和绑定装载外,Docker还支持其他装载类型和存储驱动程序,以处理更复杂、更专业的用例。要了解有关高级存储概念的更多信息,请参阅Docker中的 Manage data in Docker。
Named volumes | Bind mounts | |
---|---|---|
印射到主机的位置 | Docker 选择 | 你决定 |
Mount 示例 (使用 --mount) | type=volume,src=my-volume,target=/usr/local/data | type=bind,src=/path/to/data,target=/usr/local/data |
Populates new volume with container contents | Yes | No |
支持卷驱动 | Yes | No |
尝试绑定装载
执行 cd getting-started/app
执行 docker run -it --mount type=bind,src="$(pwd)",target=/src ubuntu bash
, Docker在容器文件系统的根目录中启动一个交互式bash会话。
在带有绑定挂载的ubuntu容器中启动bash, --mount
选项告诉Docker创建一个绑定挂载,其中src是主机上的当前工作目录getting-started/app,target是该目录应该出现在容器中的位置(/src)。
此时我们已经进入了容器, 执行 ls
可以查看容器的目录, 执行 cd src
, 执行 ls
, 发现 src 目录下内容与主机 getting-started/app 目录完全一致, 在容器内创建文件, 在主机也能看到, 两个路径已经印射起来了, 使用 Ctrl+D
快捷键可以退出容器的交互式会话
开发容器
在本地开发设置中,使用绑定挂载是很常见的。其优点是开发机器不需要安装所有的构建工具和环境。通过一个docker run命令,docker可以提取依赖项和工具。
这里用 getting-started 来演示实际开发过程中, 实时查看修改的内容
在开发容器中运行应用程序
以下步骤描述了如何使用执行以下操作的绑定装载来运行开发容器:
- 将源代码装入容器
- 安装所有依赖项
- 启动
nodemon
以监视文件系统更改
通过以下步骤运行带有绑定装载的容器。
- 确保没有 getting-started 容器在运行
- 在 getting-started/app 目录运行以下命令
docker run -dp 3000:3000 \ -w /app --mount type=bind,src="$(pwd)",target=/app \ node:18-alpine \ sh -c "yarn install && yarn run dev"
以下是部分解释
- -w /app, 设置“工作目录”或命令将从当前目录运行
- –mount type=bind,src=“$(pwd)”,target=/app, 将当前目录从主机装入容器中的/app目录
- node:18-alpine, 要使用的镜像。请注意,这是Dockerfile中应用程序的基本镜像
- sh -c “yarn install && yarn run dev”, 使用sh(alpine没有bash)启动一个shell,运行yarn install来安装包,然后运行yarn run dev来启动开发服务器。如果您查看package.json内容,您将看到dev脚本启动nodemon。
执行 docker logs <container-id>
查看容器日志, 类似如下时, 说明好了
yarn install v1.22.19
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
Done in 20.24s.
yarn run v1.22.19
$ nodemon src/index.js
[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[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”:
- 刷新浏览器, 几乎实时变化, 而 Node Server 可能需要几秒钟的时间才能重新启动
- 可以随意进行其他更改。每次进行更改并保存文件时,nodemon 进程都会自动重新启动容器中的应用程序。全部完成后,停止容器并执行
docker build -t getting-started .
可构建新镜像
多容器应用程序
通常,每个容器都应该只做一件事并做好它。即应用运行在一个容器中, 数据库运行在另一个容器中
容器网络
默认情况下,容器是孤立运行的,对同一台机器上的其他进程或容器一无所知。那么,如何允许一个容器与另一个容器进行通信呢?答案是建立网络。如果你把两个容器放在同一个网络上,它们可以相互通信。
启动 MySQL
在网络上放置容器有两种方法:
- 启动容器时分配网络。
- 将已运行的容器连接到网络。
在以下步骤中,我们将首先创建网络,然后在启动时附加MySQL容器。
执行 docker network create todo-app
创建一个网络
执行如下命令, 启动一个 MySQL 容器并将其连接到网络。我们还将定义一些环境变量,数据库将使用这些变量来初始化数据库。要了解有关MySQL环境变量的更多信息,参考 MySQL Docker Hub listing 列表中的“Environment Variables”部分。
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
在上面的命令中,有一个名为 todo-mysql-data 的卷,它安装在 /var/lib/mysql 中,这是MySQL存储数据的地方。但是,我们从未运行过 docker volume create 命令。Docker识别出您]我们想要使用一个命名卷,并自动创建了一个。
通过 --network 指定使用 todo-app 网络, 通过 --network-alias 给容器的网络起了个别名为 mysql
若要确认数据库已启动并运行,需要连接到数据库来确认
docker exec -it <mysql-container-id> mysql -u root -p
出现密码提示时,键入 secret, 执行 SHOW DATABASES;
, 执行 exit
退出容器, 至此, MySQL 容器就好了
连接到 MySQL
每个容器都有自己的IP地址。
为了更好地理解容器网络,我们先用一用 nicolaka/netshoot 容器,该容器附带了许多工具,这些工具对解决或调试网络问题非常有用。
执行 docker run -it --network todo-app nicolaka/netshoot
下载并启用该容器, 确保该容器和 MySQL 容器在同一个网络上
在该容器中,我们将使用 dig
命令,这是一个有用的DNS工具。您将查找主机名mysql的IP地址。
执行 dig mysql
得到如下的响应
; <<>> DiG 9.16.22 <<>> mysql
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 6853
;; 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: 1 msec
;; SERVER: 127.0.0.11#53(127.0.0.11)
;; WHEN: Mon Jun 19 07:45:21 UTC 2023
;; MSG SIZE rcvd: 44
在“ANSWER SECTION (应答部分)”中,我们看到mysql的一条A记录,解析为172.18.0.2(您的IP地址很可能有不同的值)。虽然mysql通常不是一个有效的主机名,但Docker能够将其解析为具有该网络别名的容器的IP地址。我们之前使用了 --network-alias。
这意味着你的应用程序只需要连接到一个名为 mysql 的主机,它就会与数据库对话。
使用 MySQL 运行应用程序
Todo 应用程序支持设置一些环境变量来指定MySQL连接设置。它们是:
- MYSQL_HOST: 运行 MySQL Server 的主机的 hostname
- MYSQL_USER: 用户名
- MYSQL_PASSWORD: 密码
- MYSQL_DB: 数据库名
在 getting-started/app 路径下执行如下命令
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:18-alpine \
sh -c "yarn install && yarn run dev"
执行 docker logs <container-id>
查看容器的日志,会看到类似于下面的消息,这表明它正在使用mysql数据库。
yarn install v1.22.19
[1/4] Resolving packages...
success Already up-to-date.
Done in 0.41s.
yarn run v1.22.19
$ nodemon src/index.js
[nodemon] 2.0.20
[nodemon] to restart at any time, enter `rs`
[nodemon] watching path(s): *.*
[nodemon] watching extensions: js,mjs,json
[nodemon] starting `node src/index.js`
Waiting for mysql:3306.
Connected!
Connected to mysql db at host mysql
Listening on port 3000
刷新浏览器, 并添加一些新的项目
执行 docker exec -it <mysql-container-id> mysql -p todos
连接到 MySQL 查看数据
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
| sys |
| todos |
+--------------------+
5 rows in set (0.00 sec)
mysql>
mysql> use todos;
Database changed
mysql>
mysql> select * from todo_items;
+--------------------------------------+------+-----------+
| id | name | completed |
+--------------------------------------+------+-----------+
| 7d57e3e3-c01e-43e1-b34a-28efa4022e0d | 111 | 0 |
| bc071de0-77d5-486f-8fb6-c9b9172ded6a | 222 | 1 |
| 29037f15-20ed-4120-8f59-bbe260d57c0e | 333 | 0 |
+--------------------------------------+------+-----------+
3 rows in set (0.00 sec)
使用 Docker Compose
Docker Compose 是一个旨在帮助定义和共享多容器应用程序的工具。使用Compose,使用Compose,我们可以创建一个YAML文件来定义服务,并使用一个命令将所有服务启动或关闭。
使用Compose的一个重要优势是,您可以在一个文件中定义应用程序堆栈,将其保留在项目存储库的根目录下(现在已进行版本控制),并轻松地让他人贡献到您的项目中。其他人只需要克隆您的存储库并启动Compose应用程序即可。实际上,在GitHub / GitLab上可能会看到现在有很多项目都在使用这种方法。
安装 Docker Compose
略
常用命令
Docker 官网文档 命令
systemctl start docker
systemctl stop docker
systemctl restart docker
docker search nginx # 检索 Nginx
docker pull nginx # 下载最新标签的 Nginx
docker images # 列出本地镜像
docker run -d --name nginx -p 80:80 nginx # 以后台模式运行 Nginx 镜像, 指定名称为 nginx, 指定端口印射 物理端口:容器端口=81:80, 容器内 nginx 默认运行在 80 端口, 指定通过物理机 81 端口访问容器的 80 端口
docker ps # 列出运行容器
docker ps -a # 列出全部容器
docker exec -it 容器id/name /bin/bash # 进入运行中的容器, -it:交互方式进入容器; 容器id只需要前几位能和其他容器区分开即可, 其他地方同样适用
exit # 退出容器
docker stop 容器id/name # 停止容器
docker rm 容器id # 删除容器
docker rm -f nginx # 删除镜像
docker commit -a mrathena -m test-commit nginx mrathena/nginx:20230616 # 将当前的容器(name:nginx)做成镜像, REPOSITORY:mrathena/nginx, TAG:20230616
帮助命令
docker version # 版本信息
docker info # 系统信息, 包括镜像和容器的数量等
docker 命令 --help
镜像命令
docker images
docker images [OPTIONS] [REPOSITORY[:TAG]]
[root@mrathena yum.repos.d]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 5 months ago 13.3kB
# REPOSITORY: 镜像的仓库源
# TAG: 镜像的标签(版本)
# IMAGE ID: 镜像的id
# CREATED: 镜像的创建时间
# SIZE: 镜像的大小
# 可选项
-a, --all # 列出所有镜像
-q, --quiet # 只显示镜像id
docker search
docker search [OPTIONS] TERM
[root@mrathena yum.repos.d]# docker search mysql
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 12216 [OK]
mariadb MariaDB Server is a high performing open sou… 4689 [OK]
mysql/mysql-server Optimized MySQL Server Docker images. Create… 907 [OK]
percona Percona Server is a fork of the MySQL relati… 570 [OK]
phpmyadmin phpMyAdmin - A web interface for MySQL and M… 465 [OK]
mysql/mysql-cluster Experimental MySQL Cluster Docker images. Cr… 93
centos/mysql-57-centos7 MySQL 5.7 SQL database server 92
bitnami/mysql Bitnami MySQL Docker Image 64 [OK]
circleci/mysql MySQL is a widely used, open-source relation… 25
ubuntu/mysql MySQL open source fast, stable, multi-thread… 24
mysql/mysql-router MySQL Router provides transparent routing be… 23
arey/mysql-client Run a MySQL client from a docker container 20 [OK]
google/mysql MySQL server for Google Compute Engine 19 [OK]
mysqlboy/docker-mydumper docker-mydumper containerizes MySQL logical … 3
mysqlboy/mydumper mydumper for mysql logcial backups 3
bitnami/mysqld-exporter 2
ibmcom/mysql-s390x Docker image for mysql-s390x 1
mysqlboy/percona-server Percona-Server a MySQL Fork with enhancement… 1 [OK]
mirantis/mysql 0
mysqlboy/elasticsearch 0
mysqleatmydata/mysql-eatmydata 0
mysql/mysql-operator MySQL Operator for Kubernetes 0
mysql/ndb-operator MySQL NDB Operator for Kubernetes 0
cimg/mysql 0
ibmcom/tidb-ppc64le TiDB is a distributed NewSQL database compat… 0
[root@mrathena yum.repos.d]# docker search mysql --filter=STARS=9999
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
mysql MySQL is a widely used, open-source relation… 12216 [OK]
docker pull
docker pull [OPTIONS] NAME[:TAG|@DIGEST]
[root@mrathena yum.repos.d]# docker pull mysql
Using default tag: latest # 不写TAG默认就是 latest 最新的
latest: Pulling from library/mysql
72a69066d2fe: Pull complete # 分层下载, docker image 核心, 联合文件系统
93619dbc5b36: Pull complete
99da31dd6142: Pull complete
626033c43d70: Pull complete
37d5d7efb64e: Pull complete
ac563158d721: Pull complete
d2ba16033dad: Pull complete
688ba7d5c01a: Pull complete
00e060b6d11d: Pull complete
1c04857f594f: Pull complete
4d7cfa90e6ea: Pull complete
e0431212d27d: Pull complete
Digest: sha256:e9027fe4d91c0153429607251656806cc784e914937271037f7738bd5b8e7709 # 签名
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest # 真实地址
[root@mrathena yum.repos.d]# docker pull mysql:5.7
5.7: Pulling from library/mysql
72a69066d2fe: Already exists # 可以直接利用已经存在的部分文件
93619dbc5b36: Already exists
99da31dd6142: Already exists
626033c43d70: Already exists
37d5d7efb64e: Already exists
ac563158d721: Already exists
d2ba16033dad: Already exists
0ceb82207cd7: Pull complete
37f2405cae96: Pull complete
e2482e017e53: Pull complete
70deed891d42: Pull complete
Digest: sha256:f2ad209efe9c67104167fc609cca6973c8422939491c9345270175a300419f94
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
docker rmi
docker rmi [OPTIONS] IMAGE [IMAGE…]
# 删除指定容器
docker rmi -f 容器id
# 删除多个容器
docker rmi -f 容器id 容器id 容器id
# 删除全部容器, 参数替换, 拿 $() 执行结果作为参数来删除
docker rmi -f $(docker images -aq)
容器命令
有镜像才可以创建容器, 下载一个linux镜像来学习测试
docker pull centos
docker run 创建容器
docker run [OPTIONS] IMAGE [COMMAND] [ARG…]
# 参数说明
--name="name" # 容器名字 用来区分容器
-d # 后台方式运行
-it # 使用交互方式运行, 方便我们进入容器查看内容
-p # 指定容器端口, -p:80:8080
-p ip:主机端口:容器端口
-p 主机端口:容器端口 (最常用)
-p 容器端口
容器端口
-P # 随机端口
# 测试, 启动并进入容器, 主机名发生变化
[root@mrathena yum.repos.d]# docker run -it centos /bin/bash
[root@434d27e6adde /]#
# 查看容器内容
[root@434d27e6adde /]# ls
bin dev etc home lib lib64 lost+found media mnt opt proc root run sbin srv sys tmp usr var
# 退出
exit # 停止容器并退出
Ctrl + P + Q # 不停止容器推出
docker ps 列出容器
docker ps [OPTIONS]
[root@mrathena yum.repos.d]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@mrathena yum.repos.d]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
434d27e6adde centos "/bin/bash" 3 minutes ago Exited (127) About a minute ago intelligent_cohen
2966bf3f4cbd hello-world "/hello" About an hour ago Exited (0) About an hour ago determined_blackwell
# 参数说明
# 列出当前正在运行的容器
-a # 列出当前正在运行的容器 + 历史运行的容器
-n=? # 列出最近创建的几个容器
-q # 只显示容器的编号
docker rm 删除容器
docker rm 容器id # 删除指定容器, 不能删除正在运行的容器, 强制删除 rm -rf
docker rm -f $(docker ps -aq)
docker ps -a -q | xargs docker rm
启动和停止容器
docker start 容器id
docker restart 容器id
docker stop 容器id # 停止运行的容器
docker kill 容器id # 强制停止运行的容器
其他常用命令
后台启动
# 后台启动
docker run -d centos
# 通过 docker ps 发现 centos 停止了, 常见的坑, docker 容器使用后台运行时要求必须有一个前台进程, 如果docker发现容器中没有应用在运行就会自动停止
docker logs 查看日志
docker logs --help
docker logs -ft --tail 10 afd77ec4f3a8
# 自己写个shell脚本
"while true; do echo hello; sleep 1; done"
[root@mrathena yum.repos.d]# docker run -d centos /bin/sh -c "while true; do echo hello; sleep 1; done"
a0dc75d7d93a5269604695f20655057e387412ab663722bd3486d5802ec7b818
[root@mrathena yum.repos.d]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a0dc75d7d93a centos "/bin/sh -c 'while t…" 3 seconds ago Up 3 seconds serene_cannon
[root@mrathena yum.repos.d]# docker logs -ft --tail 10 a0dc75d7d93a
2022-03-06T17:36:55.221020791Z hello
2022-03-06T17:36:56.222716774Z hello
2022-03-06T17:36:57.226031883Z hello
docker top 查看容器中的进程信息
[root@mrathena yum.repos.d]# docker top a0dc75d7d93a
UID PID PPID C STIME TTY TIME CMD
root 4705 4686 0 01:36 ? 00:00:00 /bin/sh -c while true; do echo hello; sleep 1; done
root 4958 4705 0 01:40 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1
docker inspect 查看容器的元数据
[root@mrathena yum.repos.d]# docker inspect a0dc75d7d93a
[
{
"Id": "a0dc75d7d93a5269604695f20655057e387412ab663722bd3486d5802ec7b818",
"Created": "2022-03-06T17:36:47.00014358Z",
"Path": "/bin/sh",
"Args": [
"-c",
"while true; do echo hello; sleep 1; done"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 4705,
"ExitCode": 0,
"Error": "",
"StartedAt": "2022-03-06T17:36:47.202311706Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6",
"ResolvConfPath": "/var/lib/docker/containers/a0dc75d7d93a5269604695f20655057e387412ab663722bd3486d5802ec7b818/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/a0dc75d7d93a5269604695f20655057e387412ab663722bd3486d5802ec7b818/hostname",
"HostsPath": "/var/lib/docker/containers/a0dc75d7d93a5269604695f20655057e387412ab663722bd3486d5802ec7b818/hosts",
"LogPath": "/var/lib/docker/containers/a0dc75d7d93a5269604695f20655057e387412ab663722bd3486d5802ec7b818/a0dc75d7d93a5269604695f20655057e387412ab663722bd3486d5802ec7b818-json.log",
"Name": "/serene_cannon",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "host",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/4a44aee72d0f2c025fdbebf35b47c87a31f48ecc342db821d20642320772e783-init/diff:/var/lib/docker/overlay2/f06b910a8a08366072e81f2eadf81bb94b9500bfd791b204dbfe80ce01ebd210/diff",
"MergedDir": "/var/lib/docker/overlay2/4a44aee72d0f2c025fdbebf35b47c87a31f48ecc342db821d20642320772e783/merged",
"UpperDir": "/var/lib/docker/overlay2/4a44aee72d0f2c025fdbebf35b47c87a31f48ecc342db821d20642320772e783/diff",
"WorkDir": "/var/lib/docker/overlay2/4a44aee72d0f2c025fdbebf35b47c87a31f48ecc342db821d20642320772e783/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "a0dc75d7d93a",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"/bin/sh",
"-c",
"while true; do echo hello; sleep 1; done"
],
"Image": "centos",
"Volumes": null,
"WorkingDir": "",
"Entrypoint": null,
"OnBuild": null,
"Labels": {
"org.label-schema.build-date": "20210915",
"org.label-schema.license": "GPLv2",
"org.label-schema.name": "CentOS Base Image",
"org.label-schema.schema-version": "1.0",
"org.label-schema.vendor": "CentOS"
}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "9aa9a53c095fc39d31cd7f2974bf08ff3b3546e2cde7603209d21107467def99",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {},
"SandboxKey": "/var/run/docker/netns/9aa9a53c095f",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "416ebf084c86aea3e061976abce95dfdc09cda0e9622dcc08c721bd6dbe10306",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:02",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "947ffb23cceba0e0444083b9a63d40159a5ed24d06e88ce71ca9a014847a93eb",
"EndpointID": "416ebf084c86aea3e061976abce95dfdc09cda0e9622dcc08c721bd6dbe10306",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.2",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:02",
"DriverOpts": null
}
}
}
}
]