首页 > 代码库 > docker知识全面讲解

docker知识全面讲解

说明:我无法使文档变得有趣,所以我只能尽力让它变得简洁和清晰,虽然你看着内容还是很多,但是只要你一步步的做下去,肯定会对docker有更深的了解。这篇文档主要是说明docker的使用,没有实际例子,下篇文档会以实例为主。

注:部分图片来自于网络,感谢分享的人。

志不坚者智不达!!!

1.docker介绍

1.1 虚拟机与容器的对比

技术分享

上图所示,容器技术相较于VM少了客户机系统这一层;底层用到了linuxLXC的容器技术,所以docker目前只能运行于linux64位系统之上(能运行32位系统也是做过处理的,降低效率),官方提供了运行于windows上的工具,但是这个工具其实是集成一个微型的virtubox虚拟机,说白了还是得需要linux系统。

 

1.2  docker组件

技术分享

Docker之所以火的很快,原因之一就是它的仓库。

仓库类似于github,很多现成的镜像供各位下载,直接用docker pull redis-server(这个名字是瞎起的)就可以拉下来一个redis服务器的镜像,放到自己的docker里就能用了,不用自己解决依赖、安装redis。好多开源工具都有docker镜像,这就使得用户只需要下载使用就行,完全省去了处理软件依赖、缺少库文件、安装部署等环节。

 

1.3  dockerOpenStack对比

技术分享

总的来说docker不如openstack强大,但是docker灵活、简单、占资源更少。

 

Docker适合微服务,一般一个docker容器只跑一个进程,连ssh服务都不要开启;像数据库这种大且重要的服务最好别用docker来跑,快慢放一边,万一有个bug就麻烦了。

docker来搭建测试环境、开发环境等都可以提高效率,还占用很少物理资源;docker其实就是轻量的虚拟机,虚拟机能干的都交给docker也行,但是要结合业务场景来看。

拿咱们公司的订单服务来说,业务高峰时订单服务变慢,那可以起20docker都跑订单服务,但假如起20个虚拟机来跑的话,抛开启动速度不说,启动瞬间可能出现IO风暴,导致磁盘IO特别高,直接影响服务质量。

2. Docker安装和镜像、容器

首先要说明的是,据传言ubuntu运行docker更快,我没有细研究过,在ubuntucentos上也都试过docker,没感觉有什么区别(可能是测试的比较浅)。看过一些资料,没觉得dockerubuntu上有什么优越的,那就更熟悉哪个用哪个吧,所以下面主要以centos为宿主系统进行测试。

 

2.1 docker安装

2.1.1 centos系统上docker安装

centos下,如果有epel源直接yum install docker-io就完成安装了。

技术分享

/etc/init.d/docker start启动docker

 

2.1.2 ubuntu系统上docker安装

sudo apt-get remove debian-keyringdebian-archive-keyring

sudo apt-get clean

sudo apt-get update && sudo apt-get-y install debian-keyring debian-archive-keyring

wget -qO- https://get.Docker.com/ | sh

:如果ubuntu启用了ufw,要配置使其能转发请求,并允许2375端口访问外网。

 

2.2镜像管理

前文说过,docker之所以这么火,就是因为它有一个类似于githubdockerhub,上面存放着很多现成的镜像,有官方的和非官方的等等。

 

dockersearch centos查询centos镜像,

技术分享

github类似,直接pull就可以把镜像拉下来,

 

dockerpull centos

可能要多pull几次才能成功。

 

技术分享

下载的centos镜像才170M,所以很多你认为该有的命令它是没有的,有个心理准备。

 

docker search

搜索镜像

docker pull

获取镜像

docker images

查看本地已有镜像

docker rm

删除镜像

docker ps

查看容器

技术分享

docker images:查看本地有什么镜像,比如有centos,有ubuntu,有redis,有elk

docker ps –a: 命令能查看所有运行的、停止的镜像的命令状态,包含容器名称、镜像名、操作命令等。

docker ps –l 查看最后一个容器的信息。

 

镜像就类似于VCenter里的镜像,容器就类似于一个真实的VMware WorkStation,容器就是通过镜像来创建的。

 

2.3 启动前台镜像

技术分享

run的作用:它首先检测有没有对应的镜像名,如果没有就自动pull,如果有就利用这个镜像来启动一个容器;

-i:进入镜像;

-t:启动一个tty终端;

/bin/bash:启动docker容器执行/bin/bash这个进程。

 

输入上图命令就会进入一个运行着/bin/bash进程的docker容器,进入后ps aux一下,发现只有一个/bin/bash进程,如下,

技术分享

在当前容器里执行exit就退出了/bin/bash进程,同时这个docker容器也就停止了。

 

重新启动一个已经停止的容器docker startcontainer-id

 

注:每一个docker容器并不是只能运行一个进程,但最好配置为只运行一个进程,不然还不如用虚拟机呢;既然容器只运行一个进程,那当这个进程结束后,docker容器也就停止了。

“—name name1”:指定容器名称为name1

“-h hostname1”:指定容器主机名为hostname1

 

2.4 启动后台镜像

启动一个后台运行的docker容器(这个进程必须支持后台运行):

技术分享

如图所示,提示本地没有nginxdocker镜像,所以它先下载nginx镜像然后再运行,然后会在后台启动一个nginx进程,必须把nginx配置为前台模式(daemon off;),不然这个容器启动一下nginx就马上退出了,前文讲过进程结束容器也就退出了。

正在运行的容器是不能直接用rm删除的,会提示加-f强制删除或者根据容器id来删。

 

正确的做法是先停止容器,docker stop container-id,然后再rm删除。目前(2016-09-22)是没法根据什么状态、什么参数来批量删除容器,只能一个个的停止、删除,但是可以通过下述命令变相做到全部删除,

docker rm `docker ps –a -q`

-a:列出所有容器。

-q:只返回容器ID

 

2.5容器管理

技术分享

2.6 进入后台容器

可以用docker attach container-id来进入一个后台容器,但是可能会进不去,直接卡住,不得不用ctrl+c来退出,但是ctrl+c后也就结束了这个容器了;

网上查着说,进入后台容器后,可以用ctrl+P+Q来退出,但是我试了试退不出来。。。

 

nsenter命令来进入后台容器更合适一点,nsenterlinux自带的命令,可以进入一个命名空间的功能,命令如下:

技术分享

使用nsenter进入容器后,直接用exit命令退出容器。

为了之后的操作方便,可以将上面的两条命令放到脚本里,一执行脚本就进入镜像了。

 

[root@salt-master docker-scripts]# cat/root/docker-scripts/mynginx.sh

#!/bin/bash

CNAME=$1

CPID=$(docker inspect --format"{{.State.Pid}}" $CNAME)

nsenter --target $CPID --mount --uts --ipc--net --pid

 

查看到mynginx里的nginxroot目录在“root   /usr/share/nginx/html;”。

:可靠资料说nsenter一般适用于docker1.2或者更早的版本,但是我在最新的版本(1.10)用着挺好,所以我一直用着这个;docker exec命令是在docker 1.3中引入的,推荐使用这个。

 

3.Docker进入容器和网络访问

技术分享

指定映射最常用的是第一种,直接指定宿主端口:容器端口;

第二种,假如宿主有多个ip的话,让容器的端口绑定到宿主的固定一个ip的端口上;

第三种,只绑定宿主ip,端口随机取;

第四种,它的意思是一条docker run命令可以同时用多次”-p”参数,指定多个端口映射关系,比如,docker run –d –p 99:80 –p 33:443 –name mynginx33 nginx

 

技术分享

启动容器时用-P(大写)参数,表示让容器随机对应一个宿主机的端口,如上,容器的80端口对应宿主的32768端口,容器的443对应宿主的32769端口。

比如我的宿主ip192.168.0.55,这时候在宿主机的浏览器输入192.168.0.55:32768就可以访问到docker容器里的nginx应用了。

端口随机映射的好处是:端口不会冲突。难点是,生产中还得用脚本或者其他方式获取到这个随机的端口,由于它是变化的,所以脚本必须得适应这种变化性。

技术分享


用小p来手动指定端口映射,如上所示,将容器的80端口映射到宿主的91端口上,而443没有指定映射关系,所以443不可访问。

 

4. Docker数据管理

技术分享

4.1 挂载数据卷

下面开始练习。

4.1.1 将容器目录挂载到宿主的随机目录

dockerrun -it --name volume-test1 -h centos-01 -v /data centos  ;创建一个名字是volume-test1,以centos系统为基础镜像的容器,它的主机名是centos-01,把这个容器的/data目录挂载到宿主机上。

重新开一个SecureCRT session,然后输入docker inspect -f{{.Volumes}} volume-test1,就会看到下面的:

map[/data:/var/lib/docker/volumes/a6d633be7da3ca959a45328f9d95f9b7db7c1f7ff9012a51ed85a0bdb7f98b94/_data]

它相当于是一个字典,把容器的/data映射到宿主的/var/lib/docker/volumes/a6d633be7da3ca959a45328f9d95f9b7db7c1f7ff9012a51ed85a0bdb7f98b94/_data

在容器的/data目录下新建一个文件,可以在/var/lib/docker/volumes/a6d633be7da3ca959a45328f9d95f9b7db7c1f7ff9012a51ed85a0bdb7f98b94/_data里看到;

同样,在宿主的

/var/lib/docker/volumes/a6d633be7da3ca959a45328f9d95f9b7db7c1f7ff9012a51ed85a0bdb7f98b94/_data里创建一个文件,也能在容器的/data目录下看到。

这个跟VMware的共享目录一模一样,一对儿目录映射关系

 

4.1.2 指定容器挂载到宿主的固定目录

dockerrun -it --name volume-test2 -h centos-02 -v /opt/centos-2:/data centos

dockerrun -it --name volume-test2 -h centos-02 -v /opt/centos-2:/data:ro centos ,这里的ro是让容器只读不可写。

 

 

上面用-v参数来建立容器和宿主的磁盘映射关系,其实是违背了docker的“一处部署,到处运行”的原则,上面的方法在Dockerfile(后文会讲到)里是不支持的。

但是这样指定磁盘映射也有好处,比如收集docker容器里的进程日志,假如在容器里再开一个logstash就不符合docker运行单进程的原则,变得臃肿,所以在所有docker容器里建一个log目录,然后都统一映射到宿主的/opt/docker-log里,然后在宿主起一个logstash进程,通过/opt/docker-log这个目录就能收集到所有docker进程的日志了。

 

4.2 数据卷容器

数据卷容器的作用实现了各容器之间的数据共享,容器不论起停都不影响数据共享,如下,

技术分享

新建的容器volume-test4共享了容器volume-test1的数据卷,所以新创建的volume-test4容器就有/data这个目录,并且这个目录下有刚才创建的文件。

 

 

 

 

 

 

 

5. 手动构建Docker镜像

构建镜像的话,现以官方的centos docker镜像为基础镜像来创建容器,进入容器后一顿yum或者一顿make,这样镜像就完成了一半了,再提交就行了。

下面实例构建一个nginx的容器。

  docker pull centos

  docker run –it –namenginx-man-construct centos

  centos容器里,安装编译安装nginx所需的依赖包,

[root@962aee9a1846 /]# yum -y install wget gcc gcc-c++openssl-devel make

  进入/usr/local/src,下载pcre,解压pcre不用安装,一会安装nginx时指定pcre的解压目录即可

  建立nginx的运行用户,useradd -s /sbin/nologin -M www

  下载nginxtar包,wget http://nginx.org/download/nginx-1.10.1.tar.gz,解压进入nginx目录,./configure--prefix=/usr/local/nginx-1.10 --user=www --group=www --with-http_ssl_module--with-http_stub_status_module --with-pcre=/usr/local/src/pcre-8.39 &&make && make install

  设置nginx开机自启动,将/usr/local/nginx/sbin/nginx加到/etc/rc.local里(这是一个坑,后面会讲到),但是这样加在平常的系统(物理机或虚拟机)里是可以自启动的,但是在容器里不行,前面说过,必须让进程运行在前台,不然容器仅仅执行一个…./nginx的启动命令就以为结束任务了,然后就退出容器了,所以要让nginx在前台运行,修改nginx.conf,在顶部加一条“daemon off;”即可。

技术分享

  yum clean all。然后退出容器,exit

  提交镜像,

技术分享

 

做完上面的步骤就创建并提交完docker镜像了,下面我们执行镜像,

docker run -d -p 92:80zhangshanci/my-nginx:v1 ,执行了这条命令,用docker ps –l查看容器状态是退出的,这是怎么回事呢?不是说设置了开机自启并且daemon off就可以了嘛,其实是把“/usr/local/nginx/sbin/nginx”加到/etc/rc.local后也不会自启动nginx,需要手动启动。我们进入镜像删除/etc/rc.local的“/usr/local/nginx/sbin/nginx”,docker run –it zhangshanci/my-nginx:v1;然后退出镜像,重新commit一次,dockercommit -m ‘create www user‘ 6df7168a3eda zhangshanci/my-nginx:v3,然后docker run–d –p 92:80 zhangshanci/my-nginx:v3 /usr/local/nginx-1.10/sbin/nginx,再docker ps –l就发现容器没有退出。

 

1:修改镜像后要重新commit;构建镜像也可以添加自启动命令或者参数,后面的构建Dockerfile会讲到。

6. Dockerfile构建 Docker镜像

Dockerfile自动构建镜像,其实就是把手动构建的命令逐行写入一个“脚本”里,只不过这个脚本有自己的语法。

现把上面手动创建nginx镜像的结果写成dockerfile形式,你会发现超级简单。

 

技术分享

这里是创建Dockerfile时会用到的语法,下面进行实际创建。

 

  mkdir -p /opt/docker-file/nginx&& cd /opt/docker-file/nginx

  vim Dockerfile   (开头字母必须大写),内容见下:

# This is my first Dockerfile

# version 1.0

# Author: shanci zhang

 

#Base images

FROM centos

 

#MAINTAINER

MAINTAINER zhangci

 

#ADD使用这个命令拷贝文件或目录(压缩包会自动解压);必须把文件拷贝到Dockerfile同目录下

ADD pcre-8.39.tar.gz /usr/local/src

ADD nginx-1.10.1.tar.gz /usr/local/src

 

#RUN

RUN yum install -y wget gcc gcc-c++ makeopenssl-devel

RUN useradd -s /sbin/nologin -M www

 

#WORKDIR 相当于cd,切换到目录

WORKDIR /usr/local/src/nginx-1.10.1

RUN ./configure--prefix=/usr/local/nginx-1.10 --user=www --group=www --with-http_ssl_module--with-http_stb_module --with-pcre=/usr/local/pcre-8.39http_stb_module--with-pcre=/usr/local/pcre-8.39 && make && make install

RUN echo "daemon off;" >>/usr/local/nginx-1.10/conf/nginx.conf

 

ENV PATH /usr/local/nginx-1.10/sbin:$PATH 

#对外开放80端口

EXPOSE 80

 

#容器启动时自动执行“nginx”命令

CMD ["nginx"]

 

  pcre-8.39.tar.gznginx-1.10.1.tar.gz拷贝到与Dockerfile的同级目录下。

  构建镜像,docker build -t nginx-dockerfile:v1 /opt/docker-file/nginx/ -t后面跟的是镜像名字,最后的路径是Dockerfile的路径)

  技术分享无需commit就能查到这个镜像了。

 

7.  Docker核心原理-资源隔离和限制

目前通过加参数可以做到cpu和内存的资源限制,但centos6还无法限制磁盘,centos7可以限制磁盘配额。

7.1 压测实验cpu和内存的限制

通过压力测试来实验限制cpu资源;在linux下使用压测工具:stress

epel源(epel6可以,epel7好像不行stress)的情况下,yum install -y stress即可完成安装。需要在容器里安装压测工具,目的是压测容器而不是压测宿主机。

 

我们先写一个Dockerfile来创建一个镜像:

vim /opt/docker-file/stress-container/Dockerfile

FROM centos

ADD epel-6.repo /etc/yum.repos.d/

RUN yum -y install stress && yumclean all

ENTRYPOINT ["stress"]

 

ENTRYPOINT ["stress"]这一行表示启动容器后,容器立刻执行stress命令并接收参数;在有这个参数的情况下,docker run -it --rm stress1 --cpu 4 这条进入容器的命令相当于docker run -it --rm stress1  stress --cpu 4,加上一个ENTRYPOINT就省去了每次启动容器都加这个命令了。

epel-6.repo下载到/opt/docker-file/stress-container目录下,然后,docker build-t stress /opt/docker-file/stress-container

 

docker run –help可以查看dockerrun可以添加的参数,

技术分享

7.2 cpu限制配额

 

-c参数:指定该容器占用宿主机cpu的权重,也可以叫配额,默认是有1024个配额,也就是满配额。

比如宿主机只有一个容器,同时该容器的配额是1024,那么启动这个容器时就可以占用宿主机的100%cpu;宿主机同样只有一个容器,该容器的配额是512-c 512,那么启动这个容器最多只能占用宿主机的50%cpu

比如有两个容器,他俩的cpu配额都是1024,那么启动这两个容器时就会各占50%cpu

比如有两个容器,A容器的cpu配额是1024B容器的cpu配额是512,那么启动这两个容器时A容器占用66%cpuB容器占用33%cpu

 

实际测验:

docker run -it --rm stress1 --cpu 1,这样就启动了一个装有stress压测工具的容器。

--rm是说容器结束后自动删除容器,--cpu 1是说占用一个cpu核心来执行stress的压测实验。

运行上面的命令后,在宿主机用top查看cpu情况,发现宿主机的cpu被这个容器占用了25%,因为我的宿主机是4核的。

结束上面的容器,然后docker run -it --rm stress1 --cpu 4,运行这个命令后,发现宿主机出来了四个stress进程,每个都占用25%,一共占用了100%的宿主机cpu

1:这里的宿主机是相对于docker来说的宿主机,这个宿主机也可能是物理机或者虚拟机。

2:安装stress压测工具的目的是让容器把它所能利用的cpu资源跑满,看看能占宿主机的百分之多少;stress这个工具会一直做运算,直到cpu跑满。

 

 

也可以通过—cpuset-cpus指定使用哪个cpu来运行容器,docker run –it –cpuset-cpus=0 stress,用第一个cpu来运行容器stress

 

7.3 内存限制配额

上面用-c—cpuset-cpus来指定cpu配额和使用哪个cpu,下面来限制内存使用。

docker run -it -m 128m --rm stress1 --cpu 8 --io 4 --vm 2--vm-bytes 500M --timeout 10s ,“-m 128m”设置stress1这个容器最大可使用宿主机128M内存,压测工具stress指定的500M的内存测试,所以随着压力增大,容器使用宿主机的内存一旦超过了128M就会触发异常并退出。

 

8. Docker核心原理-网络和Registry

Docker容器默认使用桥接模式。

8.1 桥接模式

技术分享

 

技术分享

目前起着四个容器,对应四个桥接网络,如下图,

启动docker后会创建一个虚拟网桥(用brctl show命令查看),每启动一个容器都会创建一个桥接接口,

技术分享

 

技术分享

 

宿主机和容器之间通过iptables实现端口的转换、容器上网,如下,

技术分享

 

8.2 HOST模式

每个docker容器可以选择不同的网络模式。

 

 

技术分享

host模式是容器不使用network啊、namespace什么的,直接和宿主机使用同一个网络堆栈,

这样的话容器起一个80端口,宿主机就起一个80端口,容器起一个655端口,宿主机就起一个655端口,缺点的话容器与宿主机的ip范围、端口范围等统统一样;优点就是方便,假如容器的端口与宿主机没冲突,那就可以用。

 

 

 

9. 配置私有仓库push pull

9.1 下载并运行仓库

docker pull registry

docker run –d –p 5005:5000 registryregistry的默认运行端口是5000,如果本机5000端口被占用了,可以指定一个别的端口。

9.2 找一个已有镜像打tag

docker tag zhangshanci/my-nginx:v3192.168.0.55:5005/test/nginx:v1

zhangshanci/my-nginx:v3”是镜像的名称,“192.168.0.55:5005/test/nginx:v1”是要存到仓库里的名称。

 

9.3 push镜像

高版本的dockerpush时要求有ssl数字证书,官网有三种解决办法:

  购买一个ssl证书,在所有docker容器前端配置一个nginx做反向代理;

  将下图红圈里的参数加到/etc/sysconfig/docker的启动参数里;

  自己制作一个证书,不过还是得加参数,不如方法二方便还。

技术分享

 

 

修改/etc/sysconfig/docker文件,添加启动参数:

技术分享

:这个参数也必须添加到要pull的机器上。

 

9.4 改完/etc/sysconfig/docker后重启docker、启动registry

技术分享

 

重新push镜像:

技术分享

这样push上去后,别的机器可以再pull拉下来,但是必须指定仓库的名称,如果不指定仓库名称,默认是从docker hubpull镜像。

 

 

9.5 其他机器上pull刚才的镜像

192.168.0.30上,这是centos7略有不同。

安装:yum install docker-io(有epel源前提下)

启动:systemctl start docker

9.5.1 修改/etc/sysconfig/docker,添加一个启动参数

技术分享

 

9.5.2 pull镜像

技术分享

这是一个装有nginx的镜像,以它为镜像启动一个容器,

docker run -it -p :80 30ff66a25ec4/usr/local/nginx-1.10/sbin/nginx

这样iptables –t nat –L -n就能看到本地有一个端口与容器的80端口对应,打开浏览器,输入ip:port就可以访问到容器里的nginx了。


结语:看文档本来就是一个不生动、很无聊的事,所以能坚持练习到这里,说明你很厉害哈哈。

志不坚者智不达!!!

 


docker知识全面讲解