Docker入门
Docker是一种新型的虚拟化技术,他释放了虚拟化的性能,极大的降低了云计算资源供应的成本,同时让应用的分发,测试,部署都变得非常的高效的容易!
Docker简介
Docker是一个开源项目,诞生于2013年初.使用的是Google的Go语言实现,遵循了Apache2.0协议.代码放在了GitHub上.
它使用了Linux的LXC等技术,实现了轻量级的操作系统虚拟化.
使用Docker的好处
- 更快速的交付和部署
开发者可以使用一个标准的镜像来构建一套开发容器,开发完成之后,运维人员可以直接使用这个容器来部署代码。 - 更高效的虚拟化
Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多。 - 更轻松的迁移和扩展
Docker 容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等。 这种兼容性可以让用户把一个应用程序从一个平台直接迁移到另外一个。 - 更简单的管理
所有的修改都以增量的方式被分发和更新,从而实现自动化并且高效的管理。
特性 | Docker | 虚拟机 |
---|---|---|
启动 | 秒级 | 分钟级 |
硬盘使用 | 一般为 MB | 一般为 GB |
性能 | 接近原生 | 弱于原生 |
系统支持量 | 单机支持上千个容器 | 一般几十个 |
基本概念
Docker包含了三个基本的概念:
- 镜像(Image)
- 容器(Container)
- 仓库(Repository)
理解了这三个概念,就理解了Docker的整个生命周期
镜像
- Docker镜像就是一个创建的只读模板
- 里面仅安装了最小化的操作系统和用户需要的应用程序。
- 镜像可以用来创建 Docker 容器。
容器
- 容器是从镜像创建的运行实例。
- 每个容器都是相互隔离的、保证安全的平台。
- 可以把镜像看成是一个类,而容器就是这个类的实例.
仓库
- 仓库是集中存放镜像文件的场所。
- 仓库有公有仓库和私有仓库之分
- 我们可以把自己创建的镜像注册到仓库中,提供给他人使用
- Docker 仓库的概念跟 Git 类似,注册服务器可以理解为 GitHub 这样的托管服务。
安装
由于Linux内核的限制,Docker只能安装在kernel3.8以上
最新的ubuntu14.10和centos7都已经包含了docker最新的安装源.
CentOS
直接在终端输入: sudo yum install docker
即可
然后可以输入以下命令启动并注册Docker到系统中
|
|
Ubuntu
在终端中输入以下命令安装:
|
|
最简例子
这里演示一个最简单的docker的使用例子.就是运行一个tomcat8
- 在命令行中输入:
docker search tomcat
它显示了在中央库中存在的tomcat镜像 - 从中央仓库中下载tomcat8的镜像:
在终端中输入:docker pull tomcat:8.0
这显示的就是完成从中央仓库下载镜像 - 查看当前本地docker有哪些镜像
它显示了当前有两个镜像,分别是什么,从哪下载的,镜像GUID是什么,大小是什么等等 - 从镜像中启动一个新的tomcat容器
命令是docker run -d -p 8888:8080 tomcat:8.0
-d
表示后台运行,-p
表示实体机上的端口与docker容器内的端口映射tomcat:8.0
表示镜像的名字 - 使用 docker ps -a 查看容器的状态
表示了容器的GUID,镜像名字,执行命令,创建时间,状态,端口映射,容器名字等等 - 这个时候就已经可以在浏览器中通过宿主机IP和端口8888来访问tomcat8的容器了.这样在一个什么都没有安装的新机器上,其实很简单的就完成了tomcat的安装.这就是docker的优势
常用命令
以下就是Docker的一些常用的命令.便于我们平时的操作
RUN:这个命令是最常用的命令.用于使用镜像创建一个新容器,并在其中运行给定命令.当其中的命令执行完后,关闭容器.
它的语法是:docker run 参数 镜像名:版本号
当执行这个命令后,docker会根据镜像,重新生成一个新的容器,并执行- -d:后台模式启动,这样就不会侵占当前当前的控制台
- -rm:容器执行完毕后删除容器.这功能在调试的时候非常的有用,Docker的容器开销非常的小,以至于可以随用随删除
- -ti:分配一个伪终端绑定到容器的标准输入上,并一直打开.这样就可以在实体机上操作容器的终端了.通常都是这样用的:docker run -ti tomcat:8.0 /bin/bash 这句话的意思就是启动一个新的tomcat容器,并进入它的终端
- -p:绑定容器对外访问的端口,因为默认情况下容器在docker的虚拟环境下会有自己的一个随机的虚拟IP.外面是不能直接访问的.那么如果要访问容器的应用,就需要把外面的端口和容器内的端口映射起来.这样调用实体机的某一个端口相当于是在访问docker容器中的某个端口.比如: -p 8888:8080 表示实体机的8888端口映射到容器中的8080端口.
- -name:给容器指定一个名称,如果不指定,那么就是一个随机的名字.
STOP:该命令是用来关闭容器的,使用非常的简单.
它的语法是:docker stop 容器GUID/容器名
当执行这个命令后,docker会结束此容器.当然,如果这个容器不是后台执行的.那么直接在容器的终端中输入exit也是可以结束容器的START:与Stop相反,start命令是用来启动容器的.与run命令不同的是,start命令不会从镜像中创建一个新的容器.它只会把现有的处于停止或暂停状态的容器重新启动起来.
它的语法是:docker start 参数 容器GUID/容器名
EXEC:这个命令是在某个正在运行的容器中执行某个命令.我们可以把这个命令作为进入容器环环境的一个方法.
它的语法是:docker exec 参数 容器GUID/容器名 执行的命令
.
比如:docker exec -ti c13 /bin/bash
.这个就是直接进入了容器的终端中,请注意用户那,已经是tomcat容器的上下文终端了.这个时候就可以做一系列的修改.EXPORT/IMPORT:这两个命令用于把当前执行的容器导出为快照,以及恢复快照为镜像.通过这两个命令就可以很方便的把自己对容器的修改分发给其他的人.
它们的语法是:docker export 容器GUID > 文件名.tar
和cat tar文件 | docker import 文件路径 镜像名字:版本
RM:这个指令是删除一个容器.当容器执行完毕后,如果在启动的时候没有配置-rm 那么它默认是不会删除的.这样有可能容器会越来越多.这时可以使用
docker rm 容器guid
的方式来删除不要的容器.
注意:只能删除已停止了的容器.如果没有配置数据卷,那么删除容器后,数据就会被清除PS:它可以查看当前docker中容器的情况.包括了容器的各种信息.
它的语法是:docker ps -a
可以显示所有的容器,包括已停止了的.TOP:这个命令用于显示某个docker容器中所有进程的情况.方便我们分析.
它的语法是:docker top 容器guid
SEARCH:这个命令是用来从仓库中搜寻镜像的.默认情况下,它会从中央仓库中去搜寻镜像文件.当然,你也可以指定从某个私服中去搜寻.
它的语法是:docker search 镜像关键字
PULL:使用这个命令可以从仓库中下载镜像到本地.也是很常用的一个命令.
它的语法是:docker pull 镜像名:版本号
注意:如果是从私服中下载,那么需要再镜像名前面加上私服的url/
.PUSH:与PULL命令相反,你可以把你自己做好的镜像注册到仓库中提供给他人使用.
它的语法是:docker push 镜像名字
同样,如果你要push到私服里.需要在镜像名字前使用tags
命令增加私服的url/
IMAGES:使用这个命令可以列出你现在本地有哪一些的镜像文件可以使用.
它的语法是:docker images
COMMIT:当我们对某个容器做修改之后.如果需要保留这些修改到镜像中.那么就可以是commit命令,提交修改到镜像.需要注意的是这个命令只会在原来的镜像基础上新创建一个镜像.镜像是只读的!
它的语法是:docker commit -m “提交的内容” 容器GUID 镜像名:版本
如果成功它会返回镜像的guid.SAVE/LOAD:其实这个命令和import/export是一样的.区别就在于export/import操作的对象是容器.而save/load操作的对象是镜像.
它们的语法是:docker save -o 快照名.tar 镜像名:版本
docker load < 快照名.tar
RMI:rmi命令和rm命令差不多.区别在于是用来删除无用的镜像的.
它的语法是:docker rmi 镜像名:版本
这些命令可以用下图来表示:
创建镜像
我们平时使用的时候肯定不可能只会用到现成的镜像,这就涉及到我们需要自定义镜像了.而docker提供了两种创建镜像的方法.
- 使用commit命令来提交对容器的修改,从而创建一个新的镜像.
- 使用dockerfile文件来自动化的创建一个新的镜像,这个dockerfile文件就像是Maven中的pom.xml文件一样.是用来构建镜像的脚本语言
Commit
这种方式非常简单,就是从镜像中先启动一个容器.然后进入容器,对这个容器做一些修改.而后就可以执行 docker commit
命令把这个容器保存成一个新的镜像.
但是这种方式不适合自动化构建.比如在研发过程中编译新的版本的应用程序后,每次都启动容器,进入容器,做修改,然后保存.非常的麻烦.
Dockerfile
Dockerfile用于描述如何构建一个镜像.可以使用docker build
来使用dockerfile文件.
dockerfile的每一条指令都是docker的镜像的一层操作.我们可以把docker镜像想想成是一个固定镜像上不断叠加变化的层次结构.这就是docker存储所使用AUFS.并且一个镜像不能超过127层.
dockerfile的基本语法是:
- 使用#来注释
- 以FROM指令开头,告诉Docker使用哪一镜像作为基础.
- 然后是MAINTAINER指令,表示维护者的信息
- RUN 开头的指令会在创建镜像的过程中在容器中执行.run的结果会作为下一条指令的输入.比如安装一个什么软件:
RUN yum install xxxx
- ENTRYPOINT指令用于设置在容器启动时执行的命令.每一个dockerfile中最多只能有一条这个指令.
- EXPOSE命令:设置一个端口在运行的镜像中暴露出来.这样就可以在容器外看到这个端口并与其通信.
- ENV指令:用于设置环境变量,这里设置的环境变量在以后运行的容器中都可见
- ADD指令:从src路径拷贝到容器的dest路径.注意的是src是相对于构建的源目录的相对路径.而dest是容器中的绝对路径.
- VOLUME指令:创建一个挂载点用于共享目录
- WORKDIR指令:配置RUN,CMD,ENTRYPOINT指定当前工作路径.可以设置多次,如果是相对路径,则是相对上一个WORKDIR指令的路径.
- CMD指令:同ENTRYPOINT指令差不多,用于容器启动时指定运行的命令.同样每一个dockerfile中只能有一个.它与ENTRYPOINT区别在于,执行”docker run 镜像名 命令”.的时候会替换掉CMD指令中指定的命令,而ENTRYPOINT不会.CMD可以为ENTRYPOINT提供参数,ENTRYPOINT本身也可以包含参数,但是你可以把那些可能需要变动的参数写到CMD里而把那些不需要变动的参数写到ENTRYPOINT里面.
这里提供一个案例.在一个标准的centos镜像的基础上安装tomcat.然后部署我们的一个测试的war包进去.
- 先创建一个dockertest的文件夹.在里面创建一个Dockerfile文件,注意大小写.然后写上:
- 而后在dockertest文件夹下执行:
docker build -t 镜像名字:版本 .
- 不要忘了最后的点号.那表示是在当前目录构建镜像.
- 剩下的就是等待了.
私有仓库
docker-registry 是官方提供的工具,可以用于构建私有的镜像仓库.
使用命令:
|
|
来启动私有注册中心.并指定仓库存放到实体机的/opt/data/registry
目录
可视化界面
如果觉得命令行不直观,这里还提供了一个简单的UI界面.直接使用docker下载镜像:docker pull atcol/docker-registry-ui
然后运行:docker run -d -p 8081:8080 -link registry容器的名字 atcol/docker-registry-ui
就可以了.注意它依赖registry容器.
数据管理
容器既然是非常轻量的,推崇用后即删除.那么数据存放就必然不能存放到容器内部.否则一删除容器,数据就丢失了.
Docker内部为了维护容器以及容器之间的数据.使用了数据卷和数据卷容器两种方式
数据卷
数据卷是一个可供一个或多个容器使用的特殊目录,它绕过 UFS,可以提供很多有用的特性:
- 数据卷可以在容器之间共享和重用
- 对数据卷的修改会立马生效
- 对数据卷的更新,不会影响镜像
- 卷会一直存在,直到没有容器使用
要创建一个数据卷很简单,在使用docker run
命令的时候 使用-v
参数即可.在一个run命令中可以有多个-v参数,用来指定多个数据卷.
比如:sudo docker run -d -P --name web -v /webapp training/webapp python app.py
也可以直接指定实体机的某个目录作为容器中的某个数据卷:
比如:sudo docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py
默认数据卷是 读写权限
数据卷容器
数据卷容器,其实就是一个正常的容器,专门用来提供数据卷供其它容器挂载的。
如果你有一些持续更新的数据需要在容器之间共享,最好创建数据卷容器。
然后使用run命令创建数据卷容器:sudo docker run -d -v /dbdata --name dbdata 镜像名字 echo Data-only container for it
而后启动其他容器的时候 使用—volumes-from
来挂载数据卷容器:sudo docker run -d --volumes-from dbdata --name t1 sun/tomcat
如果要删除一个数据卷,必须在删除最后一个还挂载着它的容器时使用 docker rm -v
命令来指定同时删除关联的容器。
数据卷备份
使用 --volumes-from
标记来创建一个加载 dbdata 容器卷的容器,并从宿主机挂载当前到容器的 /backup 目录。命令如下:sudo docker run --volumes-from dbdata -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata
容器启动后,使用了 tar 命令来将 dbdata 卷备份为本地的 /backup/backup.tar。
数据卷恢复
如果要恢复数据到一个容器,首先创建一个带有数据卷的容器 dbdata2。sudo docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
然后创建另一个容器,挂载 dbdata2 的容器,并使用 untar 解压备份文件到挂载的容器卷中。sudo docker run --volumes-from dbdata2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar
网络
在安装好docker以后,你操作系统的网卡中会增加一个名叫 dcoker0
的 虚拟网卡.它通常都有一个172.17.xx.xx
的IP地址.这个就是整个docker网络的桥接地址.docker容器都是通过这个桥接网卡来上网的.
每一个docker容器启动后都会随机的分配一个和docker0同网段的虚拟ip作为容器的ip.注意是每一次启动后IP地址都会改变
docker容器之间可以通过各自的虚拟ip进行互联.
docker容器外的机器除安装的宿主机外默认是不能访问容器内的ip地址的.
外部访问
如果要外部的机器访问容器内部.最简单的方式就是使用端口映射.把docker实体机的某个端口映射到docker容器内的某个端口上.这样直接访问实体机的ip:映射端口. 即可访问进容器.
- -P: Docker 会随机映射一个
49000~49900
的端口到内部容器开放的网络端口。 - -p: 则可以指定要映射的端口,并且,在一个指定端口上只可以绑定一个容器。
比如:sudo docker run -d -p 5000:5000 training/webapp python app.py
sudo docker run -d -p 127.0.0.1::5000 training/webapp python app.py
sudo docker run -d -p 127.0.0.1:5000:5000/udp training/webapp python app.py
可以通过docker port 容器GUID 端口
来查看容器的某个端口被映射成的实体机的哪个端口
-p命令可以在一个run命令中 多次使用,从而绑定多个内部端口.
垮物理机组网
外部访问的另外一种方式就是直接把容器的IP暴露到真实的网络中.不通过nat转发.
- 创建自己的网桥:
编辑/etc/network/interface
文件
将Docker的默认网桥绑定到这个新建的br0上,这样就将这台机器上容器绑定到em1这个网卡所对应的物理网络上了.
修改 /etc/default/docker
文件.最后添加一行:
在启动Docker的时候,使用-b参数将容器绑定到物理网络上,重启Docker服务后,再进入容器就可以看到它已经绑定到你的物理网络上了.
这样多台物理宿主机的容器之间也可以互联了.但是需要注意的是,这样就需要自己来保证容器的网络安全.
容器互联
除了端口映射和暴露容器到物理网络上外.容器之间的交互还有一种方式,就是使用容器的连接系统.该系统会在源和接收容器之间建立一个通信隧道,接收容器可以看到源容器指定的信息.
连接系统依赖容器的名字来执行,因此,首先需要在run的时候使用—name参数给容器起一个名字.
然后使用 —link参数让容器之间安全的进行交互.sudo docker run -d -P --name web --link db:db training/webapp python app.py
这样在启动db:db容器的时候不需要指定-P或-p. docker会自动的处理两个容器间的网络互连.你在webapp中ping db容器,是可以获取到db容器的IP的.也就可以访问db容器expose出来的端口了.
这样处理的好处就是避免了安全问题,缺点就是docker容器之外是不能访问的.通常可以把数据库等底层的容器作为link源,不暴露出对外端口. web容器通过link使用db容器.然后发布对外的访问端口映射.
容器固定IP
默认情况下启动一个container,其会自动获取一个跟docker0同网段的IP,而且重启container其IP一般会发生变化,但有时候我们会需要固定的IP(比如FT就需要固定的IP,否则每一次启动ZK中都会增加IP信息)。
要实现这个需要在docker run的时候使用—net=none的方式关闭docker默认的桥接方式连接网络.而是手动的配置网络
输入以下命令创建并进入一个tomcat容器docker run -d -P --net='none' tomcat:8.0
这个时候容器没有网卡
然后安装pipework.这个是docker开发人员提供的一个网络配置工具.
|
|
接下来使用 docker ps -a命令找到容器的名字.比如是nostalgic_almeida.
而后在实体机的终端上输入:pipework docker0 nostalgic_almeida 172.17.42.111/24
这样就给这个容器指定了172.17.42.111这个固定IP.
Pipework有个缺陷,容器重启后IP设置会自动消失,需要重新设置。这个可以写一个脚本来处理.具体的参见:http://www.aixchina.net/club/thread-123383-1-1.html