第一章 什么是docker
1.1 docker的发展史
2010年几个年轻人成立了一个做PAAS平台的公司dotCloud.起初公司发展的不错,不但拿到过一些融资,还获得了美国著名孵化器YCombinator的支持,后来微软谷歌亚马逊这样的大厂商也纷纷加入PAAS平台,竞争十分激烈,dotCloud举步维艰.
2013年可能是公司发展的不是很好,工程师又不想自己的努力付之东流,于是他们决定将他们的核心技术开源.这项技术就是docker.当时docker的功能就是将linux容器中的应用代码打包,可以轻松的在服务器之间进行迁移.
无心插柳柳成荫,docker技术风靡全球,于是dotCloud公司改名为docker Inc,并全面投入到docker的开发之中.
2014.6 Docker发布了第一个版本 Docker1.0
2014.7 获得C轮融资 $4000W
2015.4 获得D轮融资 $9500W
至今已经发布到docker
1.2 docker国内应用史
由此看出,不管开发测试还是运维,绝大多数人都应该会接触到docker。所以学docker还是很有必要的。
1.3 什么是Docker
docker是一个用来装应用的容器,就像杯子可以装水,笔筒可以放笔,书包可以放书,可以把hello word放在docker中,可以把网站放入docker中,可以把任何想得到的程序放在docker中。
官方解释:
第二章 了解docker
2.1 docker思想
2.1.1 集装箱
没有集装箱之前运输货物,东西零散容易丢失,有了集装箱之后货物不容易丢失,我们可以把货物想象成程序,目前我们要把程序部署到一台新的机器上,可能会启动不起来。比如少一些配置文件什么的或者少了什么数据,有了docker的集装箱可以保证我们的程序不管运行在哪不会缺东西。
2.1.2 标准化
1. 运输方式
docker运输东西有一个超级码头,任何地方需要货物都由鲸鱼先送到超级码头,然后再由鲸鱼从超级码头把货物送到目的地去。对应的技术来说,比如我们要把台式机的应用部署到笔记本上,我们可能选择用QQ发过去或者用U盘拷过去,docker就标准化了这个过程,我们只需在台式机上执行一个docker命令,把鲸鱼派过来,把程序送到超级码头去,再在笔记本上执行一个docker命令,然后由鲸鱼把程序从超级码头送到笔记本上去。
2. 存储方式
当我们把程序存储到笔记本上时,我们需要一个目录,且我们要记住这个目录,因为下次我们可能还要修改,有了docker之后我们就不用记住了程序在哪里了,我们使用的时候只需要一条命令就行了。
3. API接口
docker提供了一系列rest api的接口,包含了对docker也就是对我们的应用的一个启动停止查看删除等等。如当我们要启动tomcat时我们要执行startup命令,当我们要停止时要执行shutdown命令,如果不是tomcat,我们可能还需要一些别的命令。有了docker我们记docker的命令就可以对其进行操作。
2.1.3 隔离
我们在使用虚拟机时有自己的cpu、硬盘、内存,完全感觉不到外面主机的存在,docker也差不多,不过它更轻量,我们创建虚拟机可能要几分钟,但是docker只需要一秒。最底层的技术时linux一种内核的限制机制,叫做LXC,LXC是一种轻量级的容器虚拟化技术。最大效率的隔离了进程和资源。通过cgroup,namespace等限制,隔离进程组所使用的物理资源,比如CPU,MEMORY等等,这个机制在7,8年前已经加入到linux内核了,直到2013年docker出世的时候才火起来,大家可能奇怪为什么这么好的技术埋没这么多年都没人发现呢?英雄造时势,时势造英雄,如果没有云计算,敏捷开发,高频度的弹性伸缩需求,没有IT行业这么多年长足的发展,也就没有docker。
2.2 docker解决的问题
2.2.1 系统环境不一致
开发:我本地没问题。运维:服务器没问题.。
操作系统的改变可能会导致我们的应用开不起来,比如我们调用了某些系统命令。
jdk版本也可能导致程序的运行失败。比如class文件需要1.7编译,我们装了个1.6的jdk。
tomcat版本也能导致失败,比如旧的版本一些配置在新版本中不再支持。
代码的话就比如应用了C盘,D盘的一个文件,或者是用了系统的一些环境编码。
下面docker来了,它把操作系统,jdk,tomcat,代码,配置全部放到集装箱里。再打包放到鲸鱼上,由鲸鱼给我们送到服务器上,在我的机器上怎么运行,在别的机器上也怎么运行,不会有任何的问题。一句话就是docker解决了运行环境不一致所带来的问题。
2.2.2 系统好卡,哪个哥们又写了个死循环
如果有根别人共用服务器的同学可能有这样的体会,莫名其妙发现自己的程序挂了,一查原因要不是内存不够了,要不是硬盘满了,还有就是发现某个服务变慢了,甚至敲终端都比较卡,但是linux本身就是一个多用户的操作系统本身就可以供多个用户使用,docker的隔离性可以解决这个问题,就算别人的程序还是死循环疯狂吃CPU,还是封装疯狂打日志把硬盘占满,还是内存泄漏,把内存占满,都不会导致我们的程序运行错误。因为docker在启动的时候就限定好了,它最大使用的CPU硬盘,如果超过了,就会杀掉对应进程。
第三章 走进docker
镜像就是上面说的集装箱,仓库就是超级码头,容器就是我们运行程序的地方。docker运行程序的过程就是去仓库把镜像拉到本地,然后用一条命令把镜像运行起来变成容器。
build:构建,就是构建镜像。
ship:运输,运输镜像,从仓库和主机运输。
run:运行的镜像就是一个容器。
build,ship,run和镜像,仓库,容器是一一对应的。
3.1 镜像
docker 镜像是一个只读的 docker 容器模板,含有启动 docker 容器所需的文件系统结构及其内容,因此是启动一个 docker 容器的基础。docker 镜像的文件内容以及一些运行 docker 容器的配置文件组成了 docker 容器的静态文件系统运行环境:rootfs。可以这么理解,docker 镜像是 docker 容器的静态视角,docker 容器是 docker 镜像的运行状态。
rootfs
rootfs 是 docker 容器在启动时内部进程可见的文件系统,即 docker 容器的根目录。rootfs 通常包含一个操作系统运行所需的文件系统,例如可能包含典型的类 Unix 操作系统中的目录系统,如 /dev、/proc、/bin、/etc、/lib、/usr、/tmp 及运行 docker 容器所需的配置文件、工具等。
在传统的 Linux 操作系统内核启动时,首先挂载一个只读的 rootfs,当系统检测其完整性之后,再将其切换为读写模式。而在 docker 架构中,当 docker daemon 为 docker 容器挂载 rootfs 时,沿用了 Linux 内核启动时的做法,即将 rootfs 设为只读模式。在挂载完毕之后,利用联合挂载(union mount)技术在已有的只读 rootfs 上再挂载一个读写层。这样,可读写的层处于 docker 容器文件系统的最顶层,其下可能联合挂载了多个只读的层,只有在 docker 容器运行过程中文件系统发生变化时,才会把变化的文件内容写到可读写层,并隐藏只读层中的旧版本文件。
3.2 容器
为了便于理解,大家可以把容器想象成虚拟机,每个虚拟机都有自己的文件系统,可以把图1整个一部分看成是文件系统,与虚拟机系统的区别是这里面的文件系统是一层一层的,并且最下面的n层都是只读的,只有上面一层是可写的。
在程序的运行过程中,如果要写镜像文件时,因为镜像的每一层都是只读的,它会把文件的每一层拷到文件的最上层,然后再对它进行修改,修改之后,当我们的应用读一个文件时会从顶层进行查找,如果没有才会找下一层。
由于容器的最上一层是可以修改的,镜像是不能修改的,这样就能保证镜像可以生成多个容器独立运行,没有任何干扰。
3.3 仓库
我们的镜像是要在其它机器上运行,如何进行传输呢?
这就用到了docker仓库,我们要先把我们的镜像传到docker仓库中,再由目的地把docker仓库拉过去,这就完成了这样的一次传输过程。
docker自己提供了:https://hub.docker.com/,但是非常慢。
比较知名的是由网易蜂巢提供的: https://www.163yun.com/help
第四章 centos下docker安装
因为我这里使用的是centos7,所以就在centos下安装。
1. Docker 要求 CentOS 系统的内核版本高于 3.10,查看本页面的前提条件来验证你的CentOS 版本是否支持 Docker 。
通过 uname -r 命令查看你当前的内核版本
2.查看是否已安装docker列表(我的已经装过了)
yum list installed | grep docker
3. 如果安装过请先卸载,卸载有的即可,没有的不用写。
yum remove docker.x86_64 docker-client.x86_64 docker-common.x86_64
。。。 docker-latest docker-latest-logrotate docker-logrotate docker-engine
4.先更新yum(非必须,时间会较久):
yum update
遇到这类情况直接输入y就可以
5. 安装docker
yum install docker
或者使用:
yum -y install docker
-y表示不询问安装,直到安装成功,安装完后再次查看安装列表
6. 启动docker,设置开机启动
systemctl start docker
systemctl enable docker
7.验证是否安装成功
docker version
docker run hello-world
8.查看docker服务状态,显示如下即安装成功!
systemctl status docker
9.关闭docker:(注意:关闭docker,docker中的所有任务都会关闭,需要重新启动)
systemctl stop docker
10.删除镜像/容器等
rm -rf /var/lib/docker
第五章 docker体验
5.1 docker基本命令
1.docker pull [options] NAME[:TAG]
通过此命令可以docker远程仓库拉取镜像到本地。
name是拉取镜像的名称,:TAG表示是可选的,如果不选表明时latest,如果选择表明是指定版本的。
options是拉去的一些参数。
当不加请求地址的时候回去docker的官网拉取镜像。
2.docker images [options] [REPOSITORY[:TAG]]
options是选项,后面是指定镜像的名称。这个用的不多,可能当本地镜像非常多的时候要指定查看某一个镜像。
IMAGE ID 其实是一个64位的字符串,它可以唯一标识我们的镜像,这里只显示了16位,后面的被截掉了。
3. docker run [options] IMAGE[:TAG] [COMMAND] [ARG..]
IMAGE是镜像的名字。
COMMAND是运行起来的时候要执行什么命令。
ARG表示这条命令运行需要的参数。
5.2 docker运行镜像流程
docker pull:首先docker pull向docker daemon发送了一条命令pull,告诉docker daemon要拉取某一个镜像,docker daemon会在本机检查镜像是否存在,如果存在且版本就是我们想要拉取的版本,它就不会做任何的操作。如果不存在下一步它会到docker的仓库中找我们要拉取的镜像名字,如果找到了就会有docker仓库传送到我们的本地,把我们要的镜像传送到我们的本地来。
docker run:首先把命令发送到我们的docker daemon,docker daemon会先检查镜像在本机是否存在,如果不存在相当于执行了一个docker pull的过程,下载回来之后会以一定方式把镜像运行起来变成docker容器。
第六章 docker运行nginx
6.1 运行nginx镜像
我们打开网易蜂巢镜像中心 https://c.163yun.com/hub#/m/home/ ,这个需要登录。
搜索nginx,可以看到有两个nginx,他们的名字和头上和图标都不一样,一个是鲸鱼,一个是两个球。
带有鲸鱼的镜像表示这个镜像是从官网的镜像中心复制过来的.这个镜像与docker的镜像是一摸一样的,我们使用此镜像。
点进去,会有下载地址,复制里面的地址,然后拉取镜像。
复制到系统中运行:
docker pull hub.c.163.com/library/nginx:latest
运行完后可以查看镜像状态:
在前台运行容器命令如下,输入后容器就会运行,按ctrl+c可以终止容器的运行。
docker run hub.c.163.com/library/nginx
在后台运行容器:
docker run -d hub.c.163.com/library/nginx
查看运行的容器:
docker ps
更多关于运行的命令:
docker run --help
因为我们在平时运行的时候需要调试容器内部的设置、查看一下日志等等.我们可以通过如下命令进入容器内部:
命令具体内容:
docker exec -it c7d23 bash
-i保证我们的输入有效,即使在没有detach的情况下也能运行。
-t表示将分配给我们一个伪终端,我们将在伪终端输入我们的内容。
后面跟着的是容器的id,即我们上面用ps查询出来的id,这个id可以少写几位,它会自动识别。
输入命令后发现我们前面的标识也变了,相当于进入了一个新的电脑.
可以查询一下nginx在什么位置
which nginx
打开ps查看一下当前运行的进程,我这里提示没有ps命令,发现是因为当前系统没有安装这个命令,然后安装。从命令可以看出,这个nginx容器附带的系统应该是ubuntu不是centos。
ps -ef
安装ps命令:(注意:下载有点慢,可能是我的网慢把,等了好久 ^-^)
apt-get update
apt-get install procps
输入第二个命令会让你选择是否继续,输入y即可。
利用 ps -ef 命令查看进程,可以发现nginx已经在运行了。
输入 exit 即可退出返回原来的系统.。
6.2 docker网络
6.2.1 网络介绍
上面我们只运行了nginx,并没有用浏览器进行访问,这里我们尝试用浏览器访问,我们要了解一下docker网络。
我们知道docker的隔离性,网络也是个隔离性的一部分,linux使用了命名空间来进行资源的隔离,比如pid namespace就是用来隔离进程的,mount namespace是用来隔离文件系统的,network namespace 是用来隔离网络的。每一个network namespace都提供了一个独立的网络环境,包括网卡路由iptable规则等等,都是与以其它的network space隔离的。
1. docker容器在默认情况下,一般会分配一个独立的network-namespace,也就是网络类型中的Bridge模式。
在使用Bridge时就涉及到了一个问题,既然它有独立的namesapce,这就需要一种技术使容器内的端口可以在主机上访问到,这种技术就是端口映射,docker可以指定你想把容器内的某一个端口可以在容器所在主机上的某一个端口它俩之间做一个映射,当你在访问主机上的端口时,其实就是访问容器里面的端口。
2. 还有一种类型是Host模式,如果在启动容器的时候指定使用Host模式,那么这个容器将不会获得一个独立的network namespace,而是和主机共同使用一个,这个时候容器将不会虚拟出自己的网卡,配置出自己的ip。而是使用宿主机上的ip和端口。也就是说在docker上使用网络和在主机上使用网络是一样的。
3. 还有一种网络类型是None,也就是没有网络,这种情况docker将不会和外界的任何东西进行通讯。
6.2.2 实际访问端口
刚才我们在运行nginx镜像的时候并没有指定端口映射,所以我们这里停掉nginx容器。
docker stop c7d2381
1. -p(小写)是开放一个容器的端口到主机上
在后台运行,开放主机8080端口映射到容器的80端口上。
docker run -d -p 8080:80 hub.c.163.com/library/nginx
上面显示报错了,错误原因是因为8080端口被占用了,我改为8081,这个根据自己情况选择。
查看主机8081端口是否开启
netstat -na |grep 8081
如果是开启的,那么访问 ip地址:8081, 即可访问到nginx的页面。
获取本地ip地址:
ifconfig
2. -P(大写)是开放容器所有的端口到主机上一个随机的端口。
停掉刚才的docker服务,stop后面的CONTAINER ID 换成自己的。
docker stop a8fe0d86
使用大P
docker run -d -P hub.c.163.com/library/nginx
可以看到随机给我的端口是32768
然后用 ip地址:32768 即可访问到nginx的页面。
(补充内容)
https://hub.docker.com/ 这个不需要登录,在这里查,输入你要找的镜像,回车:
点击tags:
第七章 通过docker部署一个java web应用(待续。。。)
我们还需要学习Dockerfile,它告诉docker我们怎样制作我们的镜像,我们镜像的每一步操作分别是什么,写好Dockerfile后我们私用docker build命令执行Dockerfile里面的每一件事情,最终会把Dockerfile构建出来。
在这里因为是做一个演示,所以我们使用了一个开源的java web应用Jpress。
7.1 制作自己的镜像
1. 从网易的镜像中心找一个tomcat的镜像
docker pull hub.c.163.com/library/tomcat:latest
因为tomat镜像肯定有jdk,所以我们就不用单独再装jdk了,使用 docker images 查看镜像。
docker images
2.