1.1、Docker容器是什么
Docker
容器运行起来本质上就是宿主机里面的一个进程。
1.2、容器的相关操作
操作 | 作用 |
---|---|
docker run | 创建、启动一个容器 |
docker start | 启动指定容器 |
docker restart | 重新启动指定容器 |
docker stop | 停止指定容器 |
docker ps | 查看容器的状态 |
docker cp | 容器和宿主之间复制文件 |
docker exec | 执行容器中的命令 |
docker attach | 进入容器中 |
docker rm | 删除指定容器 |
docker inspect | 查看指定容器的详细信息 |
docker logs | 查看容器的操作日志 |
1.3、进入容器的正确姿势
注意:最好不要进入容器进行操作,尤其是在生产环境中!
有时候, 我们只是想要频繁的使用Ubuntu、CentOS等容器,并且也不是生产环境, 那么进入容器去执行命令是个好主意!
进入容器的方式主要有四种:
- 使用docker exec -it <containerName|containerId> /bin/bash
- 使用docker attach <containerName|containerId>
- 使用SSH
- 使用nsenter
1.3.1、docker exec
执行一个容器里面的命令。
docker exec
的帮助:

docker exec
的使用格式如下:
docker exec
的参数与docker run
的参数有几个是相同的意思:
参数 | 说明 |
---|---|
-u <username|uid> | 指定进入的容器以哪个用户登陆,默认是root |
-e <key=value> | 设置进入后可以使用的环境变量,这样动态指定比较灵活 |
-d | 以后台方式执行,这样,我们执行完这条命令,还可以干其他事情,写脚本最常用 |
-i | 以交互方式运行,是阻塞式的 |
-t | 分配一个伪终端,这个参数通常与-i 参数一起使用,然后, 在后面跟上容器里的/bin/bash ,这样就把我们带到容器里去了。 |
示例1:
sudo docker exec -u leleliu008 ubuntu ls ~
直接在宿主机中执行名称为ubuntu
的容器里面的leleliu008
用户的ls ~
命令, 这样可以避免进入容器后再出来的时候,引起不必要的麻烦!
示例2:
sudo docker exec -u leleliu008 -it 3dada3f22bd2 /bin/bash
进入ubuntu
的容器里面,以leleliu008
用户权限!
退出容器要注意了,千万别使用exit
命令,如果使用了exit
命令,退出容器的同时把容器也停止掉了, 要想退出容器,还让容器继续运行,就得先使用CTRL + P
再使用CTRL + Q
快捷键, 这样就是退出容器但不停止容器!
如果该容器是生产环境的服务器,一不小心使用了exit
命令,把容器给停止了,那就事大了!!所以,不建议直接进入容器做事情, 保险的方法还是在宿主机器中执行容器里的命令!
这么长的命令,每次都要敲多麻烦,实际上,你可以使用alias
来给这么长的命令取个别名, 放在环境变量里面,以后就直接使用别名代替那么长的命令,如下:
alias docker-enter-ubuntu='sudo docker exec -u leleliu008 ubuntu'
从这里也可以看出,为什么要给容器起一个名字,用名字而不是containerId
,在服务器上, 一般只会使用一个镜像创建一个容器,不会安装很多,所以,用名字更容易写脚本,而用containerId
每次都要修改脚本,很麻烦。
1.3.2、docker attach
当一个容器以后台方式启动后,我们想要进入这个容器,除了使用docker exec
命令外,还可以使用此命令。
docker attach
的帮助:

docker attach
的使用格式:
docker attach <containerName|containerId>
示例1:
sudo docker attach mysql5.7
示例2:
sudo docker attach 3dada3f22bd2
如果你在多个终端中使用这个命令进入容器,你在其中一个终端中执行的操作,在其他终端中是同步显示的, 这到底是好事情还是坏事情,每个人的看法不一样,不能一概而论就说他不好!但是这个命令经常会卡死,就可能与这个特性有关。 一旦在生产环境中卡死,事大了!!!所以不建议使用这个命令!
再次强调:退出容器千万别使用exit
命令,如果使用了exit
命令,退出容器的同时把容器也停止掉了, 要想退出容器,还让容器继续运行,就得先使用CTRL + P
再使用CTRL + Q
快捷键, 这样就是退出容器但不停止容器!
如果该容器是生产环境的服务器,一不小心使用了exit
命令,把容器给停止了,那就事大了!!所以,不建议直接进入容器做事情, 保险的方法还是在宿主机器中执行容器里的命令!
1.3.3、使用SSH进入容器
既然docker exec
和docker attach
进入容器这两种方法不推荐使用, 相信大家第一个想到的就是SSH
。在没有使用Docker
之前, 我们就是用SSH
进入服务器进行操作的。
很不幸,仍然是不建议使用SSH
进入到容器。至于为什么不建议这么做,请参考下面这篇文章:https://blog.docker.com/2014/06/why-you-dont-need-to-run-sshd-in-docker
中文翻译版本:http://www.oschina.net/translate/why-you-dont-need-to-run-sshd-in-docker
建议你看原文,尤其是下面的帖子回复!非常精彩!
1.3.4、使用nsenter进入容器
nsenter是util-linux中的一个小工具, 所以,要使用它,就先安装util-linux。
安装完util-linux后,我们查看nsenter
的使用帮助:

nsenter
可以访问另一个进程的名称空间。而容器运行起来实际上就是宿主机器的一个进程。 所以为了进入某个容器我们还需要获取该容器的第一个进程的PID
。 可以使用docker inspect
命令来拿到该信息,如下:
sudo docker inspect -f {{.State.Pid}} ubuntu
这样,我们就可以使用nsenter
命令访问该容器了:
sudo nsenter --target 3326 --mount --uts --ipc --net --pid
这么长的命令谁能记住呢?幸好有人帮我们做了简化工作,我们可以下载一个bash
脚本.bashrc_docker,把它放到环境变量里面就可以使用了。
wget -P ~ https://github.com/yeasy/docker_practice/raw/master/_local/.bashrc_docker; echo "[ -f ~/.bashrc_docker ] && . ~/.bashrc_docker" >> ~/.bashrc; source ~/.bashrc
这个文件中定义了很多方便使用Docker
的命令,例如docker-pid
可以获取某个容器的PID
; 而docker-enter
可以进入容器或直接在容器内执行命令。
docker-pid <containerName|containerId> docker-enter <containerName|containerId>
1.4、容器之间的通信
一个Docker
容器就是一个宿主机上的进程!所以,一般一个容器就是一个应用,比如, 我们使用nginx + Tomcat + MySQL
开发一个Java Web
应用, 我们使用Docker
容器应该如何部署呢?
假设我们的这个Java Web App
的名字叫做app1
,所以,我们在创建容器的时候, 给容器命名的时候,都以app1
开头,这样我们就很容器看出容器是哪个app
使用了。
当然,nginx
、Tomcat
、MySQL
这些软件都是可以被多个app
同时使用的, 为了便于管理,我们就不共用了。
假设我们这里的nginx
做负载均衡使用,MySQL
使用了主从复制。
下面是app1
的架构图:

我们需要创建5个Docker
容器:
app1-mysql-master
用作MySQL
主服务器。
app1-mysql-slave
用作MySQL
从服务器。
app1-tomcat-load-1
是第一个负载。它肯能访问app1-mysql-master
容器, 也可能访问app1-mysql-slave
容器。
app1-tomcat-load-2
是第二个负载。它肯能访问app1-mysql-master
容器, 也可能访问app1-mysql-slave
容器。
app1-nginx
是负载均衡调度器。 它只访问app1-tomcat-load-1
和app1-tomcat-load-2
这两个容器。
1.4.1、link机制实现容器之间的通信
很不幸,这种方式已经不建议使用了,被更好的方法取代了。官方为了兼容老版本, 这个特性仍然保留了,但是很可能在以后的某个版本被彻底废弃!
link
原理图:

要link
的容器被称为received-container
。
被link
的容器被称为source-container
。
received-container
容器可以访问source-container
容器。
实现方式是通过docker run
命令的--link <source-containerName|source-containerId:source-containerAlias>
参数。
我们使用link
机制实现一下这个例子:
1、创建app1-mysql-master
容器:
sudo docker run -d -p 3306:3306 -v ~/app1/mysql/data/master:/usr/local/mysql/data --name app1-mysql-master mysql:5.6
2、创建app1-mysql-slave
容器:
sudo docker run -d -p 3307:3306 -v ~/app1/mysql/data/slave:/usr/local/mysql/data --name app1-mysql-slave mysql:5.6
3、创建app1-tomcat-load-1
容器:
sudo docker run -d -p 8080:8080 -v ~/app1/tomcat/load-1/log:/usr/local/tomcat/log --name app1-tomcat-load-1 --link app1-mysql-master:app1-mysql-master --link app1-mysql-slave:app1-mysql-slave tomcat:8
4、创建app1-tomcat-load-2
容器:
sudo docker run -d -p 8081:8080 -v ~/app1/tomcat/load-2/log:/usr/local/tomcat/log --name app1-tomcat-load-2 --link app1-mysql-master:app1-mysql-master --link app1-mysql-slave:app1-mysql-slave tomcat:8
5、创建app1-nginx
容器:
sudo docker run -d -p 80:80 -v ~/app1/nginx/conf:/usr/local/nginx/conf --name app1-nginx --link app1-tomcat-load-1:app1-tomcat-load-1 --link app1-tomcat-load-2:app1-tomcat-load-2 nginx:1.11