docker是什么?docker不是虚拟机,是容器.
虚拟机可以理解为大房子里面的套间房,套间里面有客厅/厕所/厨房等,其他套间的使用人不能使用别人的厕所和厨房等,各自不知道各自房间里面有什么,就连房主(母机)也不知道里面有什么.
容器可以理解为大房子里面的独立房间,客厅/厕所/厨房等是公用的,所有房间的使用人都有权使用它们这些共有资源,但是各自不知道各自房间里面有什么,不过房主(母机)会知道他们占用了什么资源.
Docker是基于cgroup和lxc开发的容器工具.
cgroup原本是用来分割限制linux不同用户使用系统资源的工具.例如:A用户分配为1核cpu2G内存,B用户分配2核cpu4G内存,限制了用户使用的资源.
而lxc是基于cgroup提出的早期容器工具,不但可以分割限制资源,还可以隔离容器间的资源和通信,使其互不干扰,做到类似于虚拟机的存在,不同于虚拟机的是共享了内核和系统本身的文件系统和结构,相当轻量化,不用像虚拟机那样需要用就必须先安装整套系统,相当臃肿.不过因为安装麻烦,稳定性不佳,所以最终没有大规模使用.
最后,docker把lxc进一部改进,引入镜像功能和加强了稳定性,安装也简单,操作简单明了,而且也继承了其前任轻量化的经验,社区支持力度也很大,所以最终成为时下最流行的”微服务”的主流应用.不过也不得不说,因为功能还是比较多,很多文章也不够全面,下面转入正题.
安装
不得不说,Docker由于比较新,对于系统内核要求也要比较新,最起码要用3.1以上的内核,而3.8的内核是最好的,至于3.1以下的内核,事实上是可以使用的,但是稳定性会比较差一些,一般来说,我们选择centos7.2或ubuntu14.04以上的版本,就问题不大了,还有就是docker的版本,也尽量用最新的比较好,因为社区不断的在改进中,新版本的稳定性自然也有改善了.
安装其实很简单,因为docker类似redis,只需要命令就可以了,所以一般来说,yum安装和简单编译就可以了.
Ubuntu:
Apt-get update Apt-get install -y docker.io Ln -sf /usr/bin/docker.io /usr/local/bin/docker
Centos:
Yum install -y docker-io
关于docker安装完之后,会有一个docker的命令,以后所有相关操作都是围绕这个命令,例如下面是我们创建一个容器的简单语句:
docker run --rm -ti centos:latest /bin/bash
然后,docker默认的安装目录是/var/lib/docker/,任何和容器相关的东西都存放在这个文件夹里.不过显然这个默认目录不一定符合我们的使用标准,例如大多数人喜欢将数据盘挂载到/data目录,这样就不能很好的合理利用了.
这个时候,我们第一时间想到的是改配置文件,然而docker的配置文件不是很好改,但是也可以用软连接的方式替代原本的目录,这个方法我觉得更加通用一些和灵活一些,不过缺点就是必须停掉所有容器来做了,方法如下:
#先把docker服务停了 /etc/init.d/docker stop #创建新的docker目录路径,例如/data是数据盘 mkdir /data/dockerhome #将docker安装目录的文件全部迁移过来 mv /var/lib/docker/* /data/dockerhome/ #删了原本的目录,并创建软连接 rm -rf /var/lib/docker ln -sf /data/dockerhome /var/lib/docker #启动docker服务 /etc/init.d/docker start
这个时候你可以看到目录就是一个软连接,但这完全不影响使用
root@xxxxxx:~# ll /var/lib/docker lrwxrwxrwx 1 root root 13 Oct 17 13:25 /var/lib/docker -> /data/dockerhome/
这个时候,安装就算完成了,下面来看怎么使用,
使用
使用docker之前,除了要理解容器是什么之外,还要先理解下镜像是什么.
Docker的镜像功能正是docker优于lxc的地方,以往lxc的母机是什么发行版的系统,容器就是什么发行版的系统,例如系统是centos,那容器就必然是centos.
而docker就灵活很多,系统是什么发行版本都没所谓,可以自己编辑自己想要的镜像,也可以去社区下载别人上传的镜像,通常别人上传的镜像还有特殊的功能和软件,例如remine,java等,下载了就直接能用相关功能了,不再需要自己去安装依赖包和编译什么的,相当方便.
需要注意的是,当你安装完docker之后,并没有带有任何镜像,需要自己去下载,默认的下载地址就是docker的官网,而他们的官网在国内没有节点,时不时就被国家防火墙隔绝,会出现DNS解析不到,或者找不到镜像等狗血提示,所以如果有这些提示了,就别太惊讶了.
第三,更换下载地址,虽然默认是从官方网站下载,但是不代表不可以改,而且国内镜像站也有不少,可以考虑,不过安全性和纯净度就见仁见智了,我个人是不建议的,因为我没用过,方法也不多说了.
说了那么多,怎么下载镜像呢?其实我们说的第一条命令,就是可以自动下载镜像并创建一个容器.
docker run --rm -ti centos:latest /bin/bash
只下载镜像,不创建容器就是
docker pull centos:latest
上面两条命令都会先查找当前镜像库有没有相关名字的镜像,没有的话就去下载相关镜像名的镜像.
查找有什么镜像就用下面的命令,他列举出所有相关名字内容的docker镜像名,包含官方的,也包含社区其他用户上传的,一般来说会注明镜像包含了什么软件和功能,然后自己按需求来下载选择,这里也是docker强大的地方
docker search centos
好了,我们回归正题,这个时候,我们来研究执行第一条命令
docker run --rm -ti centos:latest /bin/bash
这条命令意思是通过镜像centos:latest创建了一个未命名的容器,run就是运行并创建容器,--rm是当容器退出就直接删除容器的意思,-ti的意思是创建了容器之后立刻进入交互模式,/bin/bash则是指定在容器内执行什么操作,一般来说,视乎镜像包含了什么软件和环境,你的容器就有什么软件和环境.
这个自然也就延伸成可以自己创建镜像,这样命令运行之后的容器,也有你当时创建镜像时的软件和环境,甚至可以自启动软件什么的.
这条命令执行之后,就会直接进入创建容器的系统内部,因为是交互模式,类似下面这样
[root@76728f45d90b /]# ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 11752 1872 ? Ss 05:56 0:00 /bin/bash root 15 0.0 0.0 47424 1652 ? R+ 05:59 0:00 ps aux
因为没有指定hostname,所以计算机名是随机的,因为是容器,不是虚拟机,不会出现除了你指定执行的程序(这里是/bin/bash)外的任何程序.
好了,既然进入了系统,其他怎么装软件和怎么装依赖包什么的,我就不打算说太多,就当做是一般虚拟机来用就行了,是ubuntu的就用apt,是centos的就用yum,自己定义好安装源就好了.我下面重点说几个基本上是必用的参数和事例.
重点讲解
先来看看常用命令和参数解析:
docker images:查看本地已经存在的镜像,-a 列出所有(默认不包括中间镜像);
docker rmi IMAGE:删除指定的镜像,-f 强制删除;
docker ps:查看运行中的 Docker 容器,-a 列出所有(默认不包括未运行的容器);
docker rm CONTAINER:删除指定的容器,-f 强制删除;
docker attach containerID:进入指定ID的容器内,不过要慎用,有隐患
docker inspect containerID:查看指定ID的容器配置
docker commit containerID 镜像名:将指定ID的容器制作成镜像,方便以后复用
-d 后台运行容器,并返回容器ID;
-i 以交互模式运行容器,通常与 -t 同时使用;
-t 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
-c分配cpu资源,不是按核数区分,可以分配1-1024任何一个数字(等同占用百分比),是一个上限值,只是注明不能超过这个数,总体cpu资源还是共享的,防止容器一挂全挂,例如分配最多二分一cpu资源给容器:-c 512
-m分配内存,支持k/m/g/t/p单位,例如分配1G内存:-m 1g
--memory-swap分配多少(非负数值)swap资源,-1即完全不分配
-p映射母机端口到容器端口,例如将母机的8001端口映射给容器的80端口:-p 8001:80
-v把母机的文件夹挂载到容器内的文件夹,例如将母机的/data/soft挂载到容器内的/soft文件夹:-v /data/soft:/soft
--name="nginx-lb" 为容器指定一个名称(和计算机名不是一回事);
--dns 8.8.8.8 指定容器使用的DNS服务器,默认和宿主一致;
--dns-search example.com 指定容器DNS搜索域名,默认和宿主一致;
-h "mars" 指定容器的hostname(和容器名不是一回事);
-e username="ritchie" 设置环境变量;
--env-file=[] 从指定文件读入环境变量;
--net="bridge" 指定容器的网络连接类型,支持 bridge /host / none
--restart=on-failure:3 容器意外停止后的操作方式,这里是尝试重启3次的意思
例如我们现在搭建了一个可以运行web的容器:
root@xxxxx:~# docker ps -a CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAME 6b21dcdefffe centos:latest "/bin/init.sh"43 hours ago Up 43 hours 0.0.0.0:22222->22/tcp testweb1
然后我们把他创建成镜像,准备复用
docker commit 6b21dcdefffe centos/test:webdemo1
最后我们创建一个自己想要的容器,要开通端口,要挂载web代码数据,那么命令就如下:
docker run -ti -e "TZ=Asia/Shanghai" --name testweb1 --restart=on-failure:3 -c 250 -m 1g --memory-swap=-1 -p 8001:80 -p 22222:22 -v /data/webdata:/data/htdocs/www centos/test:webdemo1 /bin/init.sh
意思就是创建一个容器,用镜像centos/test:webdemo1来做模板,设置时区是Asia/Shanghai,名字叫testweb1,分配了250份cpu和1G内存,把母机8001端口映射到容器的80端口,把22222端口映射给22端口,把目录/data/webdata挂载到/data/htdocs/www,在容器内运行初始化脚本/bin/init.sh(需要自己编写),这样你想要的容器就搭建完成了,你用web访问母机IP加8001端口就能访问了,想ssh登录就用22222端口.
大家看了上面的参数说明,其实就大概应该明白命令是什么意思,只是最后的/bin/init.sh是不了解为什么要这样写,后面来看一些注意事项,把一个容器真正当成服务器来使用.
注意事项
以下纯属经验之谈,是对一些容易被忽略而又比较有意思的点的总结,如果有不对,欢迎指正.
首先说说/bin/init.sh是什么东西,因为这个是我自己定义的东西,不说清楚就都不知道了.
我知道很多相关文章教启动docker都是/bin/bash,他的意思是创建一个bash会话,用处是不让容器自己退出,因为容器默认是启动并执行完命令就退出的,虽然也可以从新启动,但是任务结束了,容器也还是会退出,而启动bash会话会一直等待输入,类似死循环,所以指定容器运行/bin/bash的话,如果不主动让这个容器停止的话,就永远不会退出(除非用户发送命令退出),这样就可以随便在上面配置你想要的东西了.
而我的/bin/init.sh意义和/bin/bash差不多,只是功能更多一些,先来看看这个脚本究竟有什么东西:
#!/bin/bash touch /var/lock/subsys/local ulimit -HSn 752461 /bin/sh /etc/init.d/sshd start >/dev/null 2>&1 /bin/sh /etc/init.d/php-fpm start >/dev/null 2>&1 /bin/sh /etc/init.d/nginx start >/dev/null 2>&1 /bin/sh /etc/init.d/crond start >/dev/null 2>&1 source /etc/profile /bin/bash exit 0
我这个脚本就是启动完ssh,php-fpm,nginx,crond和加载/etc/profile之后再执行/binbash,所以才说功能和/bin/bash差不多,只是功能多了一些,至于为什么要这样做呢,正是我下面要说的事情.
从lxc开始到docker,容器终究是容器,不是虚拟机,一些本应在系统启动的时候加载的软件和环境变量并不会主动加载到容器内部,这个给我们带来的难度是有些本来应该已经加载到容器内直接使用的东西,要手动去启动和加载,相当不方便.
虽然有一些可以在创建可复用镜像前做好(例如时区和语言环境),然而有一些还是要手动执行和启动,我们终究是要解决的,所以就出现这种处理方式了,在启动容器的时候,就让他用脚本去启动和加载,也就是/bin/init.sh的用途了.
下面来说一些坑点:
比较容易解决的是时区和语言环境,容器内不一定有你需求的语言包,例如zh_CN.UTF-8这个字符集,除了你要先确保母机有这个字符集,你可能还要先安装两个软件包
yum install kde-l10n-Chinese yum reinstall glibc-common
然后
echo “export.UTF-8” >>/etc/profile
时区问题就比较狗血,如果没定义好,很可能是UTC时间,这个就要修改指定时区了,各种系统不尽相同,下面仅供参考
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
还有就是一个还不清楚原因的简单问题,linux的计划任务crontab在容器内是不能自动生效的,甚是奇怪,需要修改一个地方才可以变得和一般机器一样使用.
sed -i ‘s/required/sufficient/g‘ /etc/pam.d/crond
最后就是关于容器登录密码的问题,容器也是可能密码登录的,所以也是可以用ssh来远程连接,这也是为什么要映射22端口,和启动sshd的原因,设置密码的方法就不多说了,passwd root就是了,反正就是给root用户设置密码了,如果把容器制作成镜像,那么容器的密码也会自动随镜像加载.
上面这些做完之后,一般来说你的容器已经和一般服务器环境已经基本差不多了,然后使用类似我的脚本那样的,自动把你想要的服务(例如ssh和web相关)启动起来,加载profile环境(例如java环境)变量,这样就真的和一台服务器一样了.
其他参数列表
Attach--将终端依附到容器上
Build--通过Dockerfile创建镜像
Commit--通过容器创建本地镜像
Cp--在宿主机和容器之间相互COPY文件
Create--创建一个新的容器,注意,此时,容器的status只是Created
Diff--查看容器内发生改变的文件,以我的mysql容器为例
Events--实时输出Docker服务器端的事件,包括容器的创建,启动,关闭等。
Exec--用于容器启动之后,执行其它的任务,也可以创建容器,例如:docker exec -ti cc /bin/bash
Export--将容器的文件系统打包成tar文件
History--显示镜像制作的过程,相当于dockfile
Images--列出本机的所有镜像
Import--根据tar文件的内容新建一个镜像,与之前的export命令相对应
Info--查看docker的系统信息
Inspect--用于查看容器的配置信息,包含容器名、环境变量、运行命令、主机配置、网络配置和数据卷配置等。
Kill--强制终止容器
load --与下面的save命令相对应,将下面sava命令打包的镜像通过load命令导入
Login--登录到自己的Docker register,需有Docker Hub的注册账号
Logout--退出登录
Logs--用于查看容器的日志,它将输出到标准输出的数据作为日志输出到docker logs命令的终端上。常用于后台型容器
Pause--暂停容器内的所有进程,
Port--输出容器端口与宿主机端口的映射情况
Ps--列出所有容器,其中docker ps用于查看正在运行的容器,ps -a则用于查看所有容器。
Pull--从docker hub中下载镜像
Push--将本地的镜像上传到docker hub中
Rename--更改容器的名字
Restart--重启容器
rm --删除容器,注意,不可以删除一个运行中的容器,必须先用docker stop或docker kill使其停止。
Rmi--删除镜像
Run--让创建的容器立刻进入运行状态,该命令等同于docker create创建容器后再使用docker start启动容器
Save--将镜像打包,与上面的load命令相对应
Search--从Docker Hub中搜索镜像
Start--启动容器
Stats--动态显示容器的资源消耗情况,包括:CPU、内存、网络I/O
Stop--停止一个运行的容器
Tag--对镜像进行重命名
Top--查看容器中正在运行的进程
Unpause--恢复容器内暂停的进程,与pause参数相对应
Version--查看docker的版本
Wait--捕捉容器停止时的退出码
原文地址:http://arthur376.blog.51cto.com/2918801/1863986