Docker学习笔记(三)-- 容器

310 阅读5分钟

容器是Docker的一个核心概念。容器基于镜像创建,一个镜像能够创建多个容器。本章以mysql为例来创建容器,并介绍常用的容器命令。

创建容器

容器的创建一般由两种方式

#1.只创建容器
docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
​
#创建一个容器,并启动
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

两种方式都有许多可选项,详情参考官方文档,这里例举一些常用的参数

--name="test-mysql"     #为容器指定一个名称
-d                      #后台运行容器,并返回容器ID;
-P                      #随机端口映射,容器内部端口随机映射到主机的端口
-p                      #指定端口映射,格式为:主机(宿主)端口:容器端口
--volume , -v:          #绑定一个卷
--link=[]:              #添加链接到另一个容器,现在比较少用了。直接创建docker网络进行连接
-i                      #以交互模式运行容器,通常与 -t 同时使用,一般直接 -it
-t                      #为容器重新分配一个伪输入终端,通常与 -i 同时使用,一般直接 -it
-m                      #设置容器使用内存最大值
--cpus                  #设置cpu核心数量
--cpuset="0-2" or --cpuset="0,1,2" #绑定容器到指定CPU运行
-a stdin:               #指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项
-e username="ritchie":  #设置环境变量;

尝试创建hello-word容器和mysql容器

[root@localhost ~]# docker create hello-word
​
#这里本地hello-world不存在,所以会先从仓库下载
[root@localhost ~]# docker create hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
b8dfde127a29: Already exists 
Digest: sha256:7d91b69e04a9029b99f3585aaaccae2baa80bcf318f4a5d2165a9898cd2dc0a1
Status: Downloaded newer image for hello-world:latest
60ff238ee1d5fa13ea4aeba4eb48f5612ab771dcaa38d04583083e439b21de4e
​
# docker ps 命令查看正在运行的容器
# docker ps -a命令可以查看曾经运行的容器,这里发现多了一个容器,且状态为Created
[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE         COMMAND      CREATED          STATUS     PORTS   NAMES
60ff238ee1d5   hello-world   "/hello"     2 minutes ago    Created            affectionate_hofstadter
​
#尝试使用第二种方式创建容器
[root@localhost ~]# docker run hello-world
​
Hello from Docker! #这个容器输出了Hello from Docker
This message shows that your installation appears to be working correctly.
​
To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.
​
To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash
​
Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/
​
For more examples and ideas, visit:
 https://docs.docker.com/get-started/
​
#再次查看容器
[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE         COMMAND     CREATED              STATUS                          PORTS   NAMES
b729b0d62357   hello-world   "/hello"    About a minute ago   Exited (0) About a minute ago           nice_mirzakhani
60ff238ee1d5   hello-world   "/hello"    8 minutes ago        Created                                 affectionate_hofstadter
​
#发现,又多了一个容器,但是。该容器的状态是Exited(即退出状态)

docker容器运行必须有一个前台进程, 如果没有前台进程执行,容器认为空闲,就会自行退出。 所以第二次创建的容器在输出Hello from Docker之后就退出了。

现在尝试创建mysql容器

[root@localhost ~]# docker create mysql:5.7
8c00aba40911209bdc692017143cf14214bc5a08f020d0c0427f860120621130
#这里发现创建成功了,但是这个容器时有问题的,因为没有指定数据库的账号和密码#查看容器,发现状态为Created
[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE       COMMAND                  CREATED         STATUS                      PORTS     NAMES
8c00aba40911   mysql:5.7   "docker-entrypoint.s…"   3 minutes ago   Created                               vibrant_fermat
​
#尝试打开容器 docker start 容器id
[root@localhost ~]# docker start 8c00aba40911
8c00aba40911
[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE       COMMAND                  CREATED         STATUS                     PORTS     NAMES
8c00aba40911   mysql:5.7   "docker-entrypoint.s…"   6 minutes ago   Exited (1) 4 seconds ago             vibrant_fermat
​
#发现容器为退出状态,并没有打开,查看日志,排查问题#找到容器启动的日志文件,这个命令后文会说明。
[root@localhost ~]# docker inspect --format '{{.LogPath}}' 8c00aba40911
/var/lib/docker/containers/8c00aba40911209bdc692017143cf14214bc5a08f020d0c0427f860120621130/8c00aba40911209bdc692017143cf14214bc5a08f020d0c0427f860120621130-json.log
​
#使用cat命令查看文件内容
[root@localhost ~]# cat /var/lib/docker/containers/8c00aba40911209bdc692017143cf14214bc5a08f020d0c0427f860120621130/8c00aba40911209bdc692017143cf14214bc5a08f020d0c0427f860120621130-json.log
{"log":"2021-08-27 10:33:22+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.35-1debian10 started.\n","stream":"stdout","time":"2021-08-27T10:33:22.974193415Z"}
{"log":"2021-08-27 10:33:23+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'\n","stream":"stdout","time":"2021-08-27T10:33:23.022907959Z"}
{"log":"2021-08-27 10:33:23+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.35-1debian10 started.\n","stream":"stdout","time":"2021-08-27T10:33:23.044912579Z"}
{"log":"2021-08-27 10:33:23+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified\n","stream":"stderr","time":"2021-08-27T10:33:23.086889077Z"}
{"log":"    You need to specify one of the following:\n","stream":"stderr","time":"2021-08-27T10:33:23.086902867Z"}
{"log":"    - MYSQL_ROOT_PASSWORD\n","stream":"stderr","time":"2021-08-27T10:33:23.086904757Z"}
{"log":"    - MYSQL_ALLOW_EMPTY_PASSWORD\n","stream":"stderr","time":"2021-08-27T10:33:23.086906187Z"}
{"log":"    - MYSQL_RANDOM_ROOT_PASSWORD\n","stream":"stderr","time":"2021-08-27T10:33:23.086907527Z"}
{"log":"2021-08-27 10:37:05+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.35-1debian10 started.\n","stream":"stdout","time":"2021-08-27T10:37:05.969380202Z"}
{"log":"2021-08-27 10:37:06+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'\n","stream":"stdout","time":"2021-08-27T10:37:06.01162992Z"}
{"log":"2021-08-27 10:37:06+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.35-1debian10 started.\n","stream":"stdout","time":"2021-08-27T10:37:06.018077966Z"}
{"log":"2021-08-27 10:37:06+00:00 [ERROR] [Entrypoint]: Database is uninitialized and password option is not specified\n","stream":"stderr","time":"2021-08-27T10:37:06.059706074Z"}
{"log":"    You need to specify one of the following:\n","stream":"stderr","time":"2021-08-27T10:37:06.059721974Z"}
{"log":"    - MYSQL_ROOT_PASSWORD\n","stream":"stderr","time":"2021-08-27T10:37:06.059723974Z"}
{"log":"    - MYSQL_ALLOW_EMPTY_PASSWORD\n","stream":"stderr","time":"2021-08-27T10:37:06.059725464Z"}
{"log":"    - MYSQL_RANDOM_ROOT_PASSWORD\n","stream":"stderr","time":"2021-08-27T10:37:06.059726834Z"}
​
#最后发现 需要定义 MYSQL_ROOT_PASSWORD ,MYSQL_ALLOW_EMPTY_PASSWORD ,MYSQL_RANDOM_ROOT_PASSWORD 三个中的其中一个,容器才能正常运行#使用-e 参数添加环境变量,创建并开启容器
docker create -e MYSQL_ROOT_PASSWORD=root mysql:5.7
[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE       COMMAND                  CREATED          STATUS                      PORTS     NAMES
c246af973d89   mysql:5.7   "docker-entrypoint.s…"   6 seconds ago    Created                               blissful_pike
8c00aba40911   mysql:5.7   "docker-entrypoint.s…"   23 minutes ago   Exited (1) 16 minutes ago             vibrant_fermat
[root@localhost ~]# docker start c246af973d89
c246af973d89
[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE       COMMAND                  CREATED          STATUS                      PORTS                 NAMES
c246af973d89   mysql:5.7   "docker-entrypoint.s…"   24 seconds ago   Up 4 seconds                3306/tcp, 33060/tcp   blissful_pike
8c00aba40911   mysql:5.7   "docker-entrypoint.s…"   23 minutes ago   Exited (1) 16 minutes ago                         vibrant_fermat
​
#发现容器是开启(UP)状态,创建成功

一般来说,我们会在官网找到这个容器的安装说明,而不用这样排查

image-20210904113006640.png

现在使用官网建议的run命令来创建启动mysql容器

# --name 指定容器名称 -e设置环境变量,这里将mysql密码设置为root -d表示后台运行
​
[root@localhost ~]# docker run --name=some-mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
0c87145468c03edc3742a8063dd1d7cb6ba46e699276d81644cced4577c2b87a
[root@localhost ~]# docker ps -a
CONTAINER ID   IMAGE       COMMAND                  CREATED          STATUS                      PORTS                 NAMES
0c87145468c0   mysql:5.7   "docker-entrypoint.s…"   8 seconds ago    Up 7 seconds                3306/tcp, 33060/tcp   some-mysql
​
# 发现容器启动成功了

查看容器

#该命令用来查看容器
docker ps 
​
#常用
docker ps # 查看正在运行的容器
docker ps -a # 查看曾经运行的容器
docker ps -a - n=? # 显示最近创建的容器,设置显示个数
docker ps -aq # 只显示容器的编号,删除容器的时候很好用
docker ps --filter name=some #如果容器过多,也能模糊搜索
docker ps --last 1 #展示最后一个创建的容器

有时候,我们需要查看某个容器的详细信息,例如在使用create安装mysql的时候,需要排查容器的日志。

#该命令用来查看某个容器的详细信息,由于输出很长,可以使用--format参数来过滤
docker inspect [OPTIONS] NAME|ID [NAME|ID...]
​
#一些可选项
--format, -f: #格式化输出。
--type:# 当容器名和镜像名冲突时,可以指定类型(image/container)
--size, -s :#返回所有容器的大小
​
#使用它来查看刚才创建的some-mysql容器
[root@localhost ~]# docker inspect some-mysql
#一些常用命令#查看完整网络信息
docker inspect --format="{{json .NetworkSettings}}" container
#查看网络端口映射
docker inspect --format="{{json .NetworkSettings.Ports}}" container 
# 查看容器的网络ip、网关等信息
docker inspect --format="{{json .NetworkSettings.Networks}}" container 
# 获取容器目录挂载信息
docker inspect --format="{{json .Mounts}}" container
# 获取容器日志路径
docker inspect --format='{{.LogPath}}' container
#获取容器的镜像名
docker inspect -f "{{.Config.Image}}" container
#获取容器 MAC 地址
docker inspect --format='{{range .NetworkSettings.Networks}}{{.MacAddress}}{{end}}' container
# 获取容器 IP
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' container

进入容器

#进入容器有两种方式
docker attach #进入容器正在执行的终端,不会启动新的进程
​
#docker attach 命令在使用的时候并不方便。
#多个窗口同时attach到同一个容器时,所有窗口都会同步显示。
#而且因命令阻塞时,窗口就无法进行操作了。所以建议使用docker exec 命令来进入容器。
​
docker exec [OPTIONS] CONTAINER COMMAND [ARG...] # 进入容器后开启一个新的终端,可以在里面操作(常用)

一些可选参数

--detach,-d         #后台运行模式,在后台执行命令相关命令
--detach-keys        #覆盖容器后台运行的一些参数信息
--env, -e           #设置环境变量
--interactive, -i   #展示容器输入信息STDIN,一般和-t 一起使用
--privileged        #为命令提供一些扩展权限
--tty, -t           #命令行交互模式,一般和-i一起使用
--user, -u          #设置用户名(format: <name|uid>[:<group|gid>])
--workdir, -w       #指定容器内的目录
#使用exec命令来进入mysql容器,来查看数据库。账号密码都为root,在创建容器的时候设置过了。
[root@localhost ~]# docker exec -it some-mysql /bin/bash#在进入容器后,会直接进入这个容器的工作目录。
# mysql这里的根目录和工作目录相同。例如官方tomcat ,目录为/usr/local/tomcat。
root@0c87145468c0:/# pwd
/
root@0c87145468c0:/# mysql -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 2
Server version: 5.7.35 MySQL Community Server (GPL)
​
Copyright (c) 2000, 2021, Oracle and/or its affiliates.
​
Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.
​
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
mysql> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| sys                |
+--------------------+
4 rows in set (0.00 sec)

#退出mysql
mysql> exit;
Bye
root@0c87145468c0:/# 

退出容器

#退出容器也有两种方式
exit # 或者 ctrl + d 退出并关闭这个容器
ctrl + P + Q #容器不停止退出 注意必须在英文输入法下,中文输入法不行

停止容器

docker stop  容器id #向容器发送关闭命令
docker kill  容器id #强制关闭容器
#停止some-mysql容器
[root@localhost ~]# docker stop some-mysql
some-mysql

删除容器

docker rm                     #删除处于终止状态的容器
docker rm -f $(docker ps -aq) # 强制删除所有容器
--force , -f    #强制删除
--link , -l     #删除容器的连接
--volumes , -v  #删除数据卷

#link 和 volumes 两个命令在后文单独的章节介绍
#将some-mysql 删除
[root@localhost ~]# docker rm some-mysql
some-mysql

# 尝试删除一个状态为up的容器
[root@localhost ~]# docker rm c246af973d89
Error response from daemon: You cannot remove a running container c246af973d89e855570f9e92f3155196847a4c5cf1aef812b996b75ca5d98bd9. Stop the container before attempting removal or force remove
​
 #强制删除
[root@localhost ~]# docker rm -f c246af973d89
c246af973d89

查看容器内日志

 docker logs [OPTIONS] CONTAINER
--details #详细
-f #跟踪日志输出
--since #显示某个开始时间的所有日志
--timestamps , -t #显示时间戳
--tail , -n  #仅列出最新N条容器日志
#重新创建 some-mysql 
docker run --name=some-mysql -e MYSQL_ROOT_PASSWORD=root -d mysql:5.7
​
#查看全部日志
[root@localhost ~]# docker logs some-mysql
2021-08-27 17:14:09+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.35-1debian10 started.
2021-08-27 17:14:09+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2021-08-27 17:14:09+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.35-1debian10 started.
2021-08-27 17:14:09+00:00 [Note] [Entrypoint]: Initializing database files
# ... 中间省略
2021-08-27T17:14:19.485748Z 0 [Note] Server hostname (bind-address): '*'; port: 3306
2021-08-27T17:14:19.486190Z 0 [Note] IPv6 is available.
2021-08-27T17:14:19.486229Z 0 [Note]   - '::' resolves to '::';
2021-08-27T17:14:19.486245Z 0 [Note] Server socket created on IP: '::'.
2021-08-27T17:14:19.487586Z 0 [Warning] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
2021-08-27T17:14:19.498055Z 0 [Note] Event Scheduler: Loaded 0 events
2021-08-27T17:14:19.498302Z 0 [Note] mysqld: ready for connections.
Version: '5.7.35'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)
​
#展示最后5条
[root@localhost ~]#  docker logs -n 5 some-mysql
2021-08-27T17:14:19.486245Z 0 [Note] Server socket created on IP: '::'.
2021-08-27T17:14:19.487586Z 0 [Warning] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
2021-08-27T17:14:19.498055Z 0 [Note] Event Scheduler: Loaded 0 events
2021-08-27T17:14:19.498302Z 0 [Note] mysqld: ready for connections.
Version: '5.7.35'  socket: '/var/run/mysqld/mysqld.sock'  port: 3306  MySQL Community Server (GPL)

导入和导出容器

docker export [OPTIONS] CONTAINER #导出容器
docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]] #导入容器
#将some-mysql进行导出
[root@localhost ~]# docker export some-mysql >some-mysql.tar
[root@localhost ~]# ls
anaconda-ks.cfg  some-mysql.tar
#再将它重新导入
[root@localhost ~]# cat /root/some-mysql.tar | docker import - some-mysql:1.0
sha256:9eb51c2d237d2b0aa31d64345ac45019560bc95c4a0dfdf2f27ca22bc73978bc
[root@localhost ~]# docker images
REPOSITORY    TAG                       IMAGE ID       CREATED              SIZE
some-mysql    1.0                       9eb51c2d237d   28 seconds ago       442MB

docker loaddocker importdocker savedocker export 之间的区别:

  • docker save:将一个镜像导出为文件,再使用docker load命令将文件导入为一个镜像,会保存该镜像的的所有历史记录。比docker export命令导出的文件大。
  • docker export:将一个容器导出为文件,再使用docker import命令将容器导入成为一个新的镜像,但是相比docker save命令,容器文件会丢失所有元数据和历史记录,仅保存容器当时的状态,相当于虚拟机快照。同时导入时可以重新指定标签等元数据信息