docker容器极简教程
一,小王对于容器的困惑
小王刚开始学习Docker的时候,找资料在网上看到最多的是Docker的好处。比如:
1、Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多
2、Docker 对系统资源的利用率很高,一台主机上可以同时运行数千个 Docker 容器。
3、更快速的交付和部署、更轻松的迁移和扩展
等等……
因为小王是做java开发的,他们现有的模式是在一个服务器上安装统一一个jdk,运行多个tomcat,每个tomcat里面一个java应用,大家也知道tomcat不用安装,当他们项目要迁徙的时候也只需要把整个tomcat打包然后在另一台服务器上解压就ok了,也很简单。。。当时小王就不懂Docker有什么好处,一度以为对他们现有的模式没用。知道昨天跟其他人交流小王才弄明白一个问题,那就是应用隔离与资源独立!!
这是小王刚画的一个图,现在他们的模式是A1,所有的应用共享服务器的CPU、内存等资源,这时如果一个应用出现问题,比如CPU爆满等等,另一个应用也就玩完了。所以要这时就要做到资源独立,一个应用一份资源,现在要做到这样只有做成A2那样,一个服务器上装几个虚拟机,一个虚拟机一个应用。这时如果你要重启虚拟机,你想想你重启电脑要多久。而且你想迁移应用的话,你就又要装虚拟机,配环境等等,麻烦不?我是觉得麻烦。如果有了Docker,就是A3 的模式,容器是什么概念我就不说了,这时一个服务器上运行多个容器,一个容器拥有独立的CPU、内存等资源,完全满足了应用隔离的需求。而且容器重启,1秒搞定!应用迁移的时候,这个大家应该也知道,所有装了Docker的服务器,只需把镜像pull或者load进去,run,一切OK,就是这么任性!
二,docker教程
基本概念
Docker是基于Go语言实现的云开源项目,诞生于2013年初,最初发起者是dotCloud公司,其目标是“Build, Ship and Run Any App, Anywhere”,主要概念包括镜像、容器、仓库。Docker引擎的技术是Linux容器(Linux Containers, LXC)技术。容器有效地将由单个操作系统的资源划分到孤立的组中,以便更好地在孤立的组之间平衡有冲突的资源使用需求。
镜像Image:类似于虚拟机镜像,可以理解为面向Docker引擎的只读模板,包括文件系统。
获取镜像:docker pull NAME[:TAG]
查看镜像信息: 查看所有镜像docker images
;查看某个镜像具体信息docker inspect
添加标签: docker tag xxx ubuntu:first
搜寻镜像: docker search xxx
, -s=0
指定星级
删除镜像: docker rmi xxx
,一般情况下会删除镜像的标签,而不是文件,当删除最后一个TAG时则会删除文件,需要注意。
使用镜像ID删除镜像: -f
删除可以强制删除镜像,推荐做法为先删除依赖该镜像的所有容器,之后删除镜像,Qdocker rm e81
创建镜像: 创建镜像包括3种方式,基于已有镜像的容器创建,首先启动一个镜像docker run -ti ubuntu:14.04 /bin/bash
,任意创建一个test文件,之后创建镜像docker commit -m "add file" -a "xionger" a9fdsfxx test
;基于本地模板创建,推荐使用OpenVZ提供的模板来创建;基于Dockerfile创建。
存出镜像和载入镜像(导出、导入): 导出到本地文件sudo docker save -o ubuntu_14.04.tar ubuntu:14.04
,导入镜像docker load --input ubuntu_14.04.tar
上传镜像: docker push NAME[:TAG]
,默认上传镜像到DockerHub官方仓库,需要登录。
容器Container:类似一个轻量级的沙箱,可以利用容器来运行和隔离应用,容器从镜像启动时会在镜像的最上层创建一个可写层,镜像本身保持不变。
创建容器:docker create -it ubuntu:lastest
,通过docker ps -a
查看容器,通过docker start
启动容器
新建并启动容器:docker run ubuntu /bin/bash
,-d
参数守护态运行,通过Ctrl+d或者exit退出容器
终止容器:docker stop xxx
,首先会发送SIGTERM信号,一段时候后发送SIGKILL,可以通过docker kill
强行中止,docker restart
可以关闭并重启容器,docker ps -a -q
可以查看处于终止态的容器信息。
进入容器:docker attach xxx
会被阻塞不推荐使用;docker exec -ti xxx /bin/bash
可以直接在容器中运行命令;nsenter工具。
删除容器:docker rm xxx
,需要注意区分,rmi
是删除镜像,rm
是删除容器
导入和导出容器:docker export xxx
导出一个已经创建的容器到文件,不管是否在运行;docker import
,需要理解的是export
的是快照,信息少,而save
的是镜像,信息多,包含元数据和历史信息。
仓库Repository:类似于代码仓库,是Docker存放镜像的场所,而Registry注册服务器是存放仓库的地方,其上放着很多仓库,每个仓库集中存放某一类镜像的多个文件,可以通过tag标签来区分。目前最大的公有仓库是Docker Hub,而国内是Docker Pool。
Docker Pub:本地用户目录.dockercfg中存储登录信息,在仓库中存在centos这类由Docker公司创建、验证、支持的根镜像,也有类似xionger/centos这类由个人提供的镜像,可以通过-s N
来查看高星镜像。此外,Docker Hub还可以通过设置追踪类似GitHub的网站,然后根据其更行,自动执行创建。
创建和使用私有仓库:可以通过官方提供的registry
镜像来简单搭建一套本地私有仓库环境。
docker run -d -p 5000:5000 -v /opt/data/registry:/tmp/registry registry
docker images
docker tag ubuntu:14.04 139.196.96.27:5000/test
docker push 139.196.xx.xx:5000/test
curl http://139.196.xx.xx:5000/v1/searchdocker pull 139.196.xx.xx:5000/test
Tip:
CURL(CommandLine Uniform Resource Locator):curl是利用URL语法在命令行方式下工作的开源文件传输工具。
安装Docker(Ubuntu16.04),默认安装在/var/lib/docker
sudo apt-get install apt-transport-https
sudo apt-get update
sudo apt-get install -y docker.io
Tip:
在用putty连接阿里云时,经常会断开,如何解决?
解决方法:在Connection里面有个Seconds between keepaliaves。这里就是每间隔指定的秒数,就给服务器发送一个空的数据包,来保持连接。以免登录的主机那边在长时间没接到数据后,会自动断开SSH的连接,设置为10。
阿里云购买ECS, 操作系统版本Ubuntu 16.04(LTS)
进阶概念
数据管理:在使用docker过程中,会涉及查看容器内应用产生的数据,或者数据在多个容器间共享,此时需要管理数据的两种方式包括数据卷Data Volumes和数据卷容器Data Volume Containers.
数据卷:是一个可供容器使用的特殊目录,绕过文件系统,具有的特性包括数据卷可以在容器之间共享和重用、对数据卷的修改会马上生效、对数据卷的更新不会影响镜像、卷会一致存在,知道没有容器使用,类似Linux下对目录或文件进行mount操作。
在容器内创建一个数据卷:使用training/webapp
镜像创建一个web容器,并创建一个数据卷挂在到容器的/webapp目录,docker run -d -P --name web -v /webapp python app.py
。
挂载一个主机目录作为数据卷:加载主机的/src/webapp
目录到容器的/opt/webapp
目录,docker run -d -P --name web - v /src/webapp:/opt/webapp training/webapp python app.py
。
Tip:编辑工具包括vi或者sed --in-place,推荐挂载目录而不是文件,因为inode变化会造成docker容器启动失败。
数据卷容器:其实就是一个普通的容器,其中会挂载数据卷用户共享,创建数据库容器dbdata,之后其他容器将挂载可以挂载该数据卷容器中的数据卷。
docker run -it -v /dbdata --name dbdata ubuntu
ls
docker run -it --volumes-from dbdata --name db1 ubuntu
利用数据卷容器迁移数据:可以通过数据卷容器对其中的数据卷进行备份、回复,以实现数据的迁移。接下来的示例利用ubuntu镜像创建一个容器worker,使用--volumes-from dbdata
参数挂载dbdata容器的数据卷,
使用-v ${pwd}:/backup
参数来挂载本地的当前目录到worker容器的/backup
目录,
容器启动后,使用tar cvf /backup/backup.tar /dbdata
来讲/dbdata
下内容备份为容器内的/backup/backup.tar
。
docker run --volumes-from dbdata -v ${pwd}:/backup --name worker ubuntu tar cvf /backup/backup.tar /dbdata //恢复,首先创建一个带有数据卷的容器dbdata2,之后 创建另一个新的容器,挂载dbdata2容器,并使用untar解压备份文件到所挂载的容器卷中即可
docker run -v /dbdata --name dbdata2 ubuntu /bin/bash
docker run --volumes-from dbdata2 -v ${pwd}:/backup busybox tar xvf /backup/backup.tar
在生产环境,推荐使用分布式文件系统Ceph、GPFS、HDFS定期对主机的本地数据进行备份。
网络基础配置:
端口映射实现访问容器:在启动容器时,如果不指定对应参数,在容器外部是无法通过网络来访问容器内的网络应用和服务的。可以使用-p ip:hostPort:containerPort
映射端口,docker logs
查看应用的信息,docker port
查看端口配置。
docker run -d -p 5000:5000 -p 3000:80 training/webapp python app.py
容器互联实现容器间通信:容器见的连接系统是除了端口映射外另一种可以与容器中应用进行交互的方式,它会在源和接受容器间创建一个隧道,接受容器可以看到源容器制定的信息,比如--link
连接应用容器和数据库容器,这样可以保证db的接口不暴露到公网。
docker run -d -P --name web training/webapp python app.py
docker ps -l
docker inspect -f xxx
//容器互联
docker run -d --name db training/postgres
docker rm -f web
docker run -d -P --name web --link db:db training/webapp python app.py
docker ps
Docker通过两种方式为容器公开连接信息,包括环境变量env
和/etc/hosts文件,通过apt-get install -yqq inetutils-ping
安装ping。
扩展知识:Docker已有的实现PaaS的项目有Deis、Flynn等,持续集成方面有Drone,管理工具有Citadel, Shipyard, DockerUI等。
使用Dockerfile创建镜像
基本结构:dockerfile由命令语句组成,支持#开头的注释,分为4个部分,包括基础镜像信息、维护者信息、镜像操作指令和容器启动执行指令,在docker hub上有很多dockerfile的demo,需要时可以直接使用。
#基础镜像
FROM ubuntu
#维护者信息
MAINTAINER xionger xiongere@email.com
#镜像的操作指令
RUN apt-get update && apt-get install -y nginx
RUN echo "\ndaemon off;" >> /etc/nginx/nginx.conf
#容器启动时执行指令
CMD /usr/sbin/nginx
指令:一般格式为INSTRUCTION arguments,具体如下所示。
FROM <image>:<tag>
默认的第一条指令
MAINTAINER <name>
维护者信息
RUN <command>
或者RUN ["executable", "param1", "param2"]
,前者将在shell终端中运行命令,即/bin/sh -c
,后者则使用exec
执行。
CMD ["executable", "param1", "param2"]
使用exec
执行,推荐方式。
EXPOSE <port> [<port>..]
告诉Docker服务器容器暴露的端口号,供互联网系统使用。
ENV <key> <value>
指定一个环境变量,会被后续的RUN
指令使用
ADD <src> <dest>
该命令将复制指定到容器中的
COPY <src> <dest>
复制本地主机<src>
到容器中<dest>
,推荐使用
ENTRYPOINT ["executable", "param1", "param2"]
配置容器启动后执行的命令,不能被docker run
提供的参数覆盖
VOLUME ["/data"]
创建一个可以从本地主机或其他容器挂载的挂载点,一般用来存放数据库和需要保持的数据。
USER daemon
指定运行容器时的UID,后续的RUN
也会使用指定用户,如RUN group add -r postgres && useradd -r -g postgres postgres
,要获取管理员权限时可以使用gosu
而不是sudo
WORKDIR path/to/workdir
为后续的指令配置工作目录
ONBUILD [INSTRUCTION]
配置当所创建的镜像作为其他新创建镜像的基础镜像时,所执行的操作指令。
创建镜像:编写好dockerfile后,可以通过docker build
命令来创建镜像,该命令将读取指定路径下(包括子目录)的dockerfile,并将该路径下所有内容发送给docker服务端,由服务端来创建镜像,此外可以通过.dockerignore
文件来忽略目录或文件,还可以通过-t
指定镜像的标签信息。示例docker build -t build_repo/first_image /tmp/docker_builder/
实践之道
操作系统:CentOS和Ubuntu都可以,个人喜好ubuntu(还可以选用debian:jessie, alpine),属于最基础的镜像。
tip: 当试图安装软件出现没有相关包信息时,需要apt-get update
或编辑/etc/apt/sources.list
文件(deb, deb-src
,需要时在查询,比如163的镜像,阿里云的话无需设置),可以通过netstat -tunlp
查看当前网络情况。
支持SSH:当需要直接进入容器进行管理时安装,不必须。
Web服务器与应用(Nginx,可以使用淘宝优化的Tengine代替Nginx,Tomcat):在/usr/docker
下创建tomcat
,nginx
目录应用存放Dockerfile文件,最终还是选择通过pull拉去镜像的方式安装应用,dockerfile比较复杂。
docker pull nginx:1.12
docker ps -a
docker run --name nginx01 -p 80:80 -v $PWD/www:/www -v $PWD/conf:/etc/nginx -v $PWD/logs:/wwwlogs -d nginx:1.12
docker pull tomcat:8.0
docker run --name tomcat01 -p 8080:8080 -v $PWD/test:/usr/local/tomcat/webapps/test -d tomcat:8.0
tip:
有时可能需要重启docker服务, service docker restart
,可以选择tomcat7.0:jdk1.8
数据库应用MySQL(5.6), MongoDB(3.2), Redis(3.2)
docker pull mysql
docker run -p 3306:3306 --name mysql01 -v $PWD/conf:/etc/mysql -v $PWD/logs:/logs -v $PWD/data:/mysql_data -e MYSQL_ROOT_PASSWORD=123456 -d mysql//主从模式docker run -p 3306:3306 --name mysql01 -v $PWD/conf01:/etc/mysql -v $PWD/logs01:/logs -v $PWD/data01:/mysql_data -e MYSQL_ROOT_PASSWORD=123456 -e REPLICATION_MASTER=true -d mysql
docker run -p 3307:3306 --name mysql02 -v $PWD/conf02:/etc/mysql -v $PWD/logs02:/logs -v $PWD/data02:/mysql_data -e MYSQL_ROOT_PASSWORD=123456 -e REPLICATION_SLAVE=true --link mysql01:mysql01 -d mysql//mongodb,暂时单机,其默认提供集群的配置docker pull mongo:3.2docker run -p 27017:27017 -p 28017:28017 --name mongodb01 -v $PWD/db01:/data/db -e MONGODN_PASS="123456" -d mongo:3.2//redisdocker pull redis:3.2docker run -p 6379:6379 --name redis01 -v $PWD/data01:/data -d redis:3.2 redis-server --appendonly yes
tip:可以进入db的容器进行操作,docker exec -ti mysql /bin/bash
其他应用:maven, gitlab, jenkins, dubbo, cat,具体内容将在之后的文章中陆续介绍。
docker pull jenkins:2.60.1
docker run --name jenkins01 -p 9090:8080 -p 9091:50000 -v $PWD/jenkins01:/var/jenkins_home -d jenkins:2.60.1
构建Docker容器集群:核心问题就是让不同主机中的Docker容器相互访问,简单的方式包括两种。使用自定义网桥连接跨主机容器,Docker默认的网桥是docker0,可以通过brctl show
查看。使用Ambassador容器:当2个docker容器再同意主机时,可以通过--link相互访问,如果需要跨主机实现,则需要知道其他物理主机的IP地址。
Docker CI集成方案:在之后的Jenkins一文中将重点分析。
Tip:
目前百度BAE已经在生产环境使用Docker,Airbnb,ebay已使用mesos集成docker部署应用,此外可以使用apparmor对容器的能力进行限制。
三,docker优点
1、快速分发应用
Docker可以帮助你把控开发各个周期。Docker允许你在本地的开发环境中进行代码开发,然后将开发好的应用整合到团队的开发流程中。
比如:你可以再本地编写代码,当编写完成后。你将代码开发堆栈信息共享给团队成员。当他们也编写完成后,同样共享开发堆栈信息。然后再测试环境中,使用团队共享的开发堆栈就可以进行所需要的测试了。当完成测试后,团队就可以将测试通过的docker镜像(images)发布到产品环境中。
2、方便部署和易于管理
Docker基于容器的机制可以很容易进行部署。Docker容器可以在本地主机上面执行,也可以在虚拟机中执行,不论这些虚拟机是在本地或者云中。
Docker快速部署和轻量级的特性也使得管理负载变得很容易。你可以快速启动或者销毁容器。这种时间几乎是实时的。
3、可以执行大量的工作负载
因为Docker具有便于部署和快速启停的方式,同时docker也提供了可行的,符合效益-成本的虚拟机管理机制。使得docker很适合负载要求高的环境。比如:将你的云平台作为PAAS用途时,或者你要求你的环境具有高资源使用率时。