1、什么是docker

1.1、docker 起源

1.2、docker目标

1.3 、docker三大理念

① 构建:不仅仅是代码构建,也可以是环境 3

② 运输:运输,可以把构建环境放到任何地方。 3

③ 运行:可以在任何环境运行 3

1.4docker组成部分

1.5、docker 组件 (重点也是学习它)

1.6、docker虚拟化的不同之处

2、 为什么使用docker

2.1、docker在哪几方面具有较大优势

Docker能做什么,改变了什么?

1.简化配置

2.代码流水线管理

① 提高开发效率 7

② 快速配置开发环境 7

③ 隔离应用(没有虚拟机的效率高) 7

④ 调试能力 7

⑤ 多租互环境 7

⑥ 快速部署(比虚拟机快的多) 7

Docker重要理念不可变基础设施详解

1、什么是Immutable Infrastructure

2、Immutable Infrastructure产生背景

3、Immutable Infrastructure带来的好处

1) 解决环境间差异问题

2) 快速回滚到老版本

3) 更好的进行CI 8

4) 更好的自动化

5) 更容易进行大规模运维

Docker快速入门

1、安装docker

1.1、安装环境 8

3.10.0-514.el7.x86_64 8

1.2、安装docker

1.3、查看安装结果

2、启动docker

2.1、启动docker镜像

2.2、查看docker状态

2.3、关闭docker

2.4、查看本地网络

3、基础命令讲解

1. 镜像

2. 容器

3. 仓库

3.1、镜像命令

3.1.2查看已有镜像

3.1.1、搜索

3.1.2、下载

3.1.3 导出镜像

、导入镜像

3.1.6删除镜像

创建镜像

3.2容器

3.2.1、启动容器

① 基于镜像新建一个容器并启动。

② 将终止状态的容器重新启动。

3.2.2、启动已经终止的容器

、后台运行

3.2.3、进入镜像

已经起来的镜像怎么进去

3.2.3.1、attach 15

3.2.3.2、 nsenter  进入到命名空间里面

利用docker inspect 获得PID号

① –mount参数是进去到mount namespace中 16

② –uts参数是进入到uts namespace中 16

③ –ipc参数是进入到System V IPC namaspace中 16

④ –net参数是进入到network namespace中 16

⑤ –pid参数是进入到pid namespace中 16

⑥ –user参数是进入到user namespace中 16

我们不能每次都要执行上面的命令,找到PID 在进入再次我们需要写一个脚本

3.2.3.3、docker exec

3.2.4、查看容器列表

3.2.5、容器删除

Docker进入容器和网络访问

随机映射:

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

数据管理

4.1 挂载数据卷

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

4.1.2 指定容器挂载到宿主的固定目录 生产常用的

测试:

4.2 数据卷容器 类似nfs 差不多  其实生产不用

4.  手动构建Docker镜像,生产不常用,一般都是自动化

6. 由Dockerfile构建 Docker镜像  重点中重点,难点中难点

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

实际测验:

内存限制配额

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

8.1 桥接模式

8.2 HOST模式

配置私有仓库push 和

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

9.5.2 pull镜像

10生产构建docker镜像核心思想,生产案例演示


1、什么是docker

1.1、docker 起源

开源项目

诞生2013年初

GO语言开发实现

遵从了Apache2.0协议

项目代码在GitHub维护

、docker目标

docker项目目标是实现轻量级的操作解约方案。

linux容器(LXC)等技术,在LXC的基础上进行了封装,让用户不需要关心docker的管理,使得操作更为简单。

 

1.3 、docker三大理念

① 构建:不仅仅是代码构建,也可以是环境

② 运输:运输,可以把构建环境放到任何地方。

③ 运行:可以在任何环境运行

一次创建,处处运行

 

可以做一些整体的交付(不一定是代码 交付,可以是运行环境和代码放到一起构建,可以提供运行环境和代码)

 

核心思想:环境不变可以不用docker,看业务使用,不同业务会有不同的契合度。

引入新技术的原因:解决痛点,做技术储备

 

通俗点解释:

就像docker的log一样,鲸鱼(操作系统)和集装箱(存放各种服务应用),我们需要把各种各样的货物放到鲸鱼身,你得为每件货物考虑,怎么安放(应用程序所需要的环境),考虑货物与货物之间是否合适(应用程序依赖环境是否冲突)。

现在我们只要把货物放入到集装箱里,就可以安全的存放,稳定,方便。

 

1.4docker组成部分

C/S架构

Docker Client    执行docker命令属于客户端

Docker server    docker进程属于客户端

注:docker服务端挂掉所有的客户端也会挂掉,这是docker的一个痛点

 

1.5、docker 组件 (重点也是学习它)

① 镜像(Image):和虚拟机镜像作用完全一样,但是组成部分不同。

② 容器(Container):从镜像创建的一个实例(类似虚拟机),相互之间隔离的,不会像虚拟机那样隔离的彻底。可以理解为简化版的linux环境。用容器来运行业务的,可以理解为一个简化版的linux系统环境

③ 仓库(Repository):镜像仓库,镜像做好可以放进去,所有服务器只要可以连接到仓库,都可以直接下载,相当与yum仓库。docker自己也有一个docker hub。

 

1.6、docker虚拟化的不同之处

可见容器实在操作系统层面实现虚拟化,直接复用本地主机的操作系统,而传统虚拟化方式则是在硬件层面实现的。  简要的说就是虚拟机是虚拟  docker是隔离

 

核心思想:对新技术的选择在实验科研中一定是最新要敢为人先,生产中一定不要敢为人先,让别人先去踩坑

 

虚拟机和docker的实现原理和区别:对内核要求高,这也是搞火ubuntu的原因

 

 

Docker与OpenStack的区别  核心思想理念  拿项目管理考试和现实来讲解做对比

虚拟机需要运行hypervisor,docker都跑在docker引擎里面,docker不是虚拟机,没有操作系统直接运行应用。

 

docker无法像虚拟机一样提供完全的资源隔离,甚至好多地方都没有隔离,比如用户空间,一直再填坑,体验新功能需要内核支持。

 

类别

Docker

OpenStack/kvm

部署难度

非常简单

组件多,部署复杂

启动速度

秒级

分钟级

执行性能

和物理系统几乎一致

VM会占用一些资源

镜像体积

镜像是MB级别

虚拟机镜像GB级别

管理效率

管理简单

组件相互依赖,管理复杂

隔离性

隔离性高

彻底隔离

可管理性

单进程、不建议启动SSH

完整的系统管理

网络连接

比较弱

借助Neutron可以灵活组件各类网络架构

需要注意:

 

  1. docker里面只能启动一个单进程,还是在前台,如果挂了docker就直接退出。
  2. docker容器就是一个进程,挂了也就挂了,按照docker理念不需要打开ssh,不需要连接上。 容器挂了再重新启动一个。
  3. docker 管理简单 管理简单以为操作的简单,没有办法想怎么管怎么管,在复杂的环境管理简单就不是优势了。
  4. 单进程  可以写一个脚本里面写多个进程解决,但是这有不符合docker理念,只要启动一个就好了。套件可以跑,php+nginx 可以 但是直接跑lnmp就不符合docker的理念了。

 

2、为什么使用docker

如果保障环境一致性:  快速回滚?  回到上一个版本? 虚拟化快照来实现  为什么需要虚拟环境呢,比如我要升级一个软件,结果就把所有依赖的包都升级了,那就出故障了。

 

标准化和规范性

 

docker项目的发起人和Docker.Inc的CTO 认为,docker在正确的地点、时间顺应了正确的趋势即高效地构建应用,现在开发者需要能方便地创建运行在云平台的应用,也就是说应用必须能够脱离底层机器,而且同时是任何时间任何地点可获取的。因此开发者需要创建一种分布式应用程序的方式,这也是docker所能够提供的。

 

docker通过容器来打包应用,这样我们就可以在新的机器上启动这个容器就可以了,这无疑节约了大量的时间,并且大大降低了部署过程中的错误。并且可以支持把代码和容器打包,这样我们就可以直接启动容器做相应的测试,上线。真正做到了一次搭建,处处运行。

 

2.1、docker在哪几方面具有较大优势

① 更快的交付和部署

对于开发和运维人员来说,最希望的就是一次创建或配置,可以在任意地方运行。

开发者可以使用一个标准的镜像来构建一套开发容器,开发完成后,运维人员开一直接使用这个容器来部署代码。

② docker可以快速创建容器,快速迭代应用程序,并让整个过程全程可见,使团队中的其他成员更容易理解应用程序是如何创建和工作的。

③ Docker很轻很快!容器启动时间是 秒级,大量地节约开发、测试、部署的时间。

 

④ 更高效虚拟化

 

docker容器的运行不需要额外的hypervisor支持,它是内核级的虚拟化,因此可以实现更高的性能和效率。

 

 

⑤ 更轻松的迁移和扩展

Docker容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等。这种兼容性可以让用户把一个应用程序从一个平台直接迁移到另一个。

 

 

⑥ 更简单的管理

使用docker,只需要小小的修改就可以替代大量更新工作。所有的修改都以增量的方式被分发和更新,从而实现自动化并且高效的管理

 

Docker能做什么,改变了什么?

 

 

1.简化配置

主要应用场景,把代码和运行环境放到一起,这样就不需要什么代码部署,直接启动容器就是一个服务。不许要环境部署和代码上线

 

代码流水线管理

传统流程:开发写代码--测试--运维上线 docker 可以避免这么复杂的流程

 

docker管理这个流水线,开发保存镜像,测试run起来测试,测试结束,运维run起来跑,(虚拟机太大也可以实现),一次构建到处运行

 

① 提高开发效率

② 快速配置开发环境

③ 隔离应用(没有虚拟机的效率高)

④ 调试能力

⑤ 多租互环境

⑥ 快速部署(比虚拟机快的多)

 

开发也好测试也好运维也好,要使用的话直接yum一个docker,然后从仓库导入一下,整个环境就可以工作了

 

赵班长总结:

面向产品 :产品交付  安全,把什么成果代码都打包进docker一起交付

面向开发: 简化配置环境 ,只用告诉开发下载一个docker就行了,本地不需要环境

面向测试: 多版本测试

面向运维: 环境一致性

面向架构: 自动化扩容(微服务)

 

 

Docker重要理念不可变基础设施详解

1、什么是Immutable Infrastructure

Immutable Infrastructure,直译过来就是不可变基础设施。

它是由Chad Fowler于2013年提出的一个很有前瞻性的构想。

基础设备中的每层的每个组件都可以自动安装、部署。

每个组件在完成后将将不会发生更改,如果要更改,则丢弃老的组件并部署一个新的组件。

这种思想与不可变对象的概念完全相同。

这里所说的每一层,指的是从os(虚拟机、云主机)到集群,节点管理和单个节点的安装软件配置。

2、Immutable Infrastructure产生背景

当然在很多年以前这个概念是得不到技术支持的,我们很难在不同的物理机上实现软件的不可变。

不过随着虚拟化技术以及云计算的发展,现在这已经变得可能了。

我们更多的时候,面对的不是一台台的物理主机,更多的是云主机实例。

安装一个操作系统也不需要几小时,而只需要鼠标点几下,等上两三分钟即可。

重装系统这个概念已经不存在,删掉一个主机实例我们也不会心疼。

 

3、Immutable Infrastructure带来的好处

1) 解决环境间差异问题

2) 快速回滚到老版本

3) 更好的进行CI

4) 更好的自动化

5) 更容易进行大规模运维

 

 

Docker快速入门

 

 

 1、安装docker

1.1、安装环境

[root@linux-node1 ~]# cat /etc/redhat-release

CentOS Linux release 7.3.1611 (Core)

[root@linux-node1 ~]# uname -r

3.10.0-514.el7.x86_64

1.2、安装docker

yum install docker -y

1.3、查看安装结果

[root@linux-node1 ~]# rpm -qa docker

docker-1.13.1-63.git94f4240.el7.centos.x86_64

[root@linux-node1 ~]# docker --version

Docker version 1.13.1, build 94f4240/1.13.1 

我们可以通过官方的docker官网下载最新版本。

Docker官网:http://www.docker.com/

注:使用docker目前使用的越新越好,因为docker一直都在不足,每次更新都更加的完善。

2、启动docker

2.1、启动docker镜像

[root@docker ~]# systemctl start docker

2.2、查看docker状态

[root@docker ~]# systemctl  status docker

2.3、关闭docker

systemctl stop docker

2.4、查看本地网络

 

docker启动后,会生成一个docker:0的网卡(虚拟机也会生成)。

 

3、基础命令讲解

 以docker的三大组件,分别讲解命令。

  1. 镜像
  2. 容器
  3. 仓库

3.1、镜像命令

docker 运行容器前需要本地存在对应的镜像,如果镜像本地不存在,docker会从镜像仓库下载(默认从Docker Hub仓库下载)。

3.1.2查看已有镜像

 

docker images

[root@docker ~]# docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

oldboy/nginx1       latest              c436de4b837a        5 days ago          401.1 MB

oldboy/nginx        v1                  99695fe97fb5        5 days ago          181.4 MB

docker.io/nginx     latest              05a60462f8ba        3 weeks ago         181.4 MB

docker.io/centos    latest              0584b3d2cf6d        4 weeks ago         196.5 MB

 在列出的信息中,可以看到几个字段的信息

  • 来自于那个仓库(REPOSITORY)
  • 镜像标记(TAG)
  • 它的ID号(唯一)
  • 创建时间
  • 镜像大小

 

3.1.1、搜索

docker search [镜像名称]

例:查看dockerhub中nginx的镜像。

[root@docker ~]# docker search nginx

 

3.1.2、下载

docker pull [镜像名称]

例:下载docker.io/centos/redis

 docker pull  docker.io/centos/redis

Using default tag: latest

Trying to pull repository docker.io/centos/redis ...

latest: Pulling from docker.io/centos/redis

3.1.3 导出镜像

docker save -o [镜像包名] [镜像名称]

例:导出centos基础镜像为centos.tar

[root@docker ~]# docker images

[root@docker ~]# docker save -o centos.tar docker.io/centos

[root@docker ~]# ll -h centos.tar -rw-r--r-- 1 root root 195M Dec  1 20:54 centos.tar

、导入镜像

docker load --input [镜像包名]

[root@linux-node1 ~]# docker load --input centos.tar

 

docker load <[镜像包名]

3.1.6删除镜像

docker rni [镜像id]

例:删除一个镜像

[root@docker ~]# docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

oldboy/nginx1       latest              c436de4b837a        5 days ago          401.1 MB<none>              <none>              6ab373e100c9        5 days ago          181.4 MB

oldboy/nginx        v1                  99695fe97fb5        5 days ago          181.4 MB

docker.io/nginx     latest              05a60462f8ba        3 weeks ago         181.4 MB

docker.io/centos    latest              0584b3d2cf6d        4 weeks ago         196.5 MB

daemon: conflict: unable to delete 0584b3d2cf6d (cannot be forced) - image has dependent child images

[root@docker ~]# docker rmi 6ab373e100c9

[root@docker ~]# docker images

REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE

oldboy/nginx1       latest              c436de4b837a        5 days ago          401.1 MB

oldboy/nginx        v1                  99695fe97fb5        5 days ago          181.4 MB

docker.io/nginx     latest              05a60462f8ba        3 weeks ago         181.4 MB

docker.io/centos    latest              0584b3d2cf6d        4 weeks ago         196.5 MB

注:不能删除已有容器的镜像

例:删除一个已有容器的镜像

[root@docker ~]# docker rmi 0584b3d2cf6d

Failed to remove image (0584b3d2cf6d): Error response from daemon: conflict: unable to delete 0584b3d2cf6d (cannot be forced) - image has dependent child images

例:移除本地所有未打过标签的本地镜像

docker images可以列出本地所有的镜像,其中可能包含很多中间状态的来打过标签的镜像,大量占据着磁盘空间。

使用下面命令可以清理所有未打过标签的本地镜像

docker rmi $(docker images -q -f "danglingture")

 

创建镜像

创建镜像为较为复杂点,在之后的文档中会详细介绍。 所有重难点都在这里!

 

3.2容器

容器是独立运行的一个或一组应用,以及他们的运行环境。对应的虚拟机可以理解为模拟运行的一套操作系统(提供了运行环境和其他其系统环境)和跑在上面的应用。

3.2.1、启动容器

启动容器的方式

① 基于镜像新建一个容器并启动。

② 将终止状态的容器重新启动。

容器太轻量了,很多时候用户都是随时删除和新创建容器。

docker run [选项、参数] 镜像名称 [执行的命令] 

注:如果不指定镜像名称会自动生成名称,管理docker一般都是以名称或者id号来管理的

例:输出一个hell[root@docker ~]# docker run docker.io/centos /bin/echo 'hello world'

hello world

这跟直接在本地执行一个hello world 没有任何区别。

 

[root@docker ~]# docker ps -a 查看docker启动状态  不加-a的话只显示正在运行的

 

 

因为没有指定容器名称,所以他自己自动生成了gigantic_sinoussi

例:启动一个bash,允许用户交互,指定容器名称为mycentos

[root@docker ~]# docker run -i -t --name mycentos docker.io/centos (镜像名) /bin/bash  如果后面不是命令,最后就必须是镜像名

[root@c761cee8863f /]#

-name:指定容器名称-t:让docker分配一个伪终端

-i:让容器的标准输入打开(input)

接上例:在交互模户,模式下。用户可以通过所创建的终端来输入命令

[root@c761cee8863f /]# pwd/

[root@c761cee8863f /]# ls

anaconda-post.log  bin  dev  etc  home  lib  lib64  lost+found  media  mnt  opt  proc  root  run  sbin  srv  sys  tmp  usr  var

继续接上例:在可交互模式查看进程,本地信息

root@c761cee8863f /]# ps aux

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

root         1  0.0  0.0  11752  1876 ?        Ss   15:44   0:00 /bin/bash

root        17  0.0  0.0  47424  1660 ?        R+   16:02   0:00 ps aux

[root@c761cee8863f /]# free -m

              total        used        free      shared  buff/cache   available

Mem:           1993         158        1121           8         713        1669

Swap:           475           0         475

[root@c761cee8863f /]# exit

[root@docker ~]# free -m

              total        used        free      shared  buff/cache   available

Mem:           1993         147        1140           8         706        1681

Swap:           475           0         475

 

容器不是一个虚拟机,他只是一个进程,pid为1的进程结束了,这个容器就挂了,他就是为了隔离这个进程而存在的。

 

docker的隔离性并不是很好,在物理机可以看到服务器的硬件信息,docker本身不能解决,但是可以用一些黑科技解决,当然如果自己用的话也可以不用解决这个问题。

docker run来创建容器时,docker在后台运行的标准操作包括:

  1. 检查本地是否存在 指定的镜像,不存在就从仓库下载。
  2. 利用镜像创建并启动一个镜像
  3. 分配一个文件系统,并在只读的镜像层外面挂载一层可读写层。
  4. 从宿主主机配置的网桥接口中桥接一个虚拟接口到容器中去
  5. 从地址池配置一个ip地址给容器
  6. 执行用户指定的应用程序
  7. 执行完毕后容器被终止

3.2.2、启动已经终止的容器

 

docker start [容器名称|容器id]

例:启动mycentos

[root@docker ~]# docker ps

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

[root@docker ~]# docker ps -a

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                      PORTS               NAMES

c761cee8863f        docker.io/centos    "/bin/bash"              35 minutes ago      Exited (0) 18 minutes ago                       mycentos

ccfc03f90613        docker.io/centos    "/bin/echo /bin/bash"    36 minutes ago      Exited (0) 36 minutes ago                       elated_brown

443da0721b41        docker.io/centos    "/bin/echo 'hello wor"   44 minutes ago      Exited (0) 44 minutes ago                       gigantic_sinoussi

[root@docker ~]# docker start mycentos

mycentos

[root@docker ~]# docker ps

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

c761cee8863f        docker.io/centos    "/bin/bash"         36 minutes ago      Up 3 seconds                            mycentos

注:有的人想在容器起来的时候在执行其他的东西。这是不推荐的因为docker的理念,不可变基础设施,不要修改容器(前面有讲解),再重新创建一个就可以了,已改动就可变了。

、后台运行

更多的时候需要让Docker 在后台运行而不是直接执行命令的结果输出在当前宿主机下,此时,可以通过添加 -d 参数来实现。

例:如果不使用-d参数运行容器

 [root@docker ~]# docker run   centos echo hello world

hello world

容器会把输出结果打印到宿主机上

例:使用-d参数

[root@docker ~]# docker run  -d centos echo hello world

f6f8844f843b6479ab2d9faf52aef55a8c9516effa1dc7574299989025f24a41

[root@docker ~]# docker logs f6f8844f843b6479ab2d9faf52aef55a8c9516effa1dc7574299989025f24a41

hello world

 这时候容器会在后台运行并不会把输出结果(STDOUT)打印到宿主机上面(输出结果可以用docker logs查看)
注:容器是否会长久运行,是和docker run指定的

3.2.3、进入镜像

已经起来的镜像怎么进去

Centos 7命令补全工具:

yum -y install bash-completion 自动补全命令

3.2.3.1、attach  

docker attach [镜像名称]

这个登录相当于单用户模式,只能有一个人登录。一般生产不推荐使用此法。

例:一方操作另一方会自动操作。

 

命令不靠谱

3.2.3.2、 nsenter进入到命名空间里面

生产场景是不使用docker attach的,需要我们使用nsenter这个工具,这个工具包含在util-linux软件包里面。nsenter可以访问另一个进程的名字空间。nsenter要正常工作需要有root权限。

[root@docker ~]#  yum install util-linux -y

一般情况下最小化安装里都已经安装完毕。

我们通过nsenter就可以进入容器,但是nsenter是通过容器第一个进程的pid进入容器里,所以我们需要知道容器的pid。我们可以通过docker inspect来获取到pid

利用docker inspect 获得PID号

[root@docker ~]# docker start mycentos

mycentos

[root@docker ~]# docker inspect -f "{{ .State.Pid }}" mycentos

10656

[root@docker ~]# nsenter -t 10656 -m -u -i -n -p

[root@c761cee8863f /]#

那个参数选项是简写全称的就是:

nsenter --traget $PID  --mount --uts  --ipc --net --pid

nsenter参数:

① –mount参数是进去到mount namespace中

② –uts参数是进入到uts namespace中

③ –ipc参数是进入到System V IPC namaspace中

④ –net参数是进入到network namespace中

⑤ –pid参数是进入到pid namespace中

⑥ –user参数是进入到user namespace中

 我们进入容器查看进程

[root@c761cee8863f /]# ps aux

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

root         1  0.0  0.0  11776  1664 ?        Ss+  22:06   0:00 /bin/bash

root        14  0.0  0.0  13376  1988 ?        S    22:12   0:00 -bash

root        27  0.0  0.0  49024  1808 ?        R+   22:21   0:00 ps aux

其中/bin/bash 是我们开启容器运行的第一个进程

-bash 是nsenter 启动时生成的进程,这样我们退出后,容器不会退出,仍然会运行。

我们不能每次都要执行上面的命令,找到PID 在进入再次我们需要写一个脚本

写脚本思想,先把框架写出来

 cat  cat docker_in.sh

#!/bin/bash

# Use nsenter to access docker

docker_in(){

  NAME_ID=$1

  PID=$(docker inspect -f "{{ .State.Pid }}" $NAME_ID)

  nsenter -t $PID -m -u -i -n -p

}

docker_in $1

执行结果

[root@docker ~]# chmod +x docker_in.sh

[root@docker ~]# ./docker_in.sh mycentos

[root@c761cee8863f /]# ps aux

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

root         1  0.0  0.0  11776  1664 ?        Ss+  22:06   0:00 /bin/bash

root        28  0.0  0.0  13376  1984 ?        S    22:28   0:00 -bash

root        41  0.0  0.0  49024  1812 ?        R+   22:28   0:00 ps aux

3.2.3.3、docker exec

docker exec 的本意不是为了进入容器,仅仅是为了在外面执行一个容器的操作。

docker exec [容器名称|id] 命令

例:在容器mycentos外执行命令whoami等

[root@docker ~]# docker exec mycentos whoami

root

[root@docker ~]# docker exec mycentos ps aux

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND

root         1  0.0  0.0  11776  1664 ?        Ss+  22:06   0:00 /bin/bash

root        46  0.0  0.0  47424  1660 ?        Rs   22:34   0:00 ps aux

进入容器方法

docker exec -it [容器名称|id] /bin/bash

例:使用docker exec 进入容器

[root@docker ~]# docker ps

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

c761cee8863f        docker.io/centos    "/bin/bash"         6 hours ago         Up 30 minutes                           mycentos

[root@docker ~]# docker  exec -it mycentos  /bin/bash

[root@c761cee8863f /]# exit

[root@docker ~]# docker  exec -it c761cee8863f  /bin/bash

[root@c761cee8863f /]#

和 nsenter 实现原理不一样 实现结果一样的 推荐使用脚本进入是最佳实现

3.2.4、查看容器列表

docker ps

例:查看正在运行的容器

[root@docker ~]# docker ps

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

c761cee8863f        docker.io/centos    "/bin/bash"         6 hours ago         Up 32 minutes                           mycentos

例:查看所有容器

[root@docker ~]# docker ps -a

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS               NAMES

edfdd26e20da        centos              "echo hello world"       3 hours ago         Exited (0) 3 hours ago                         kickass_heisenberg

f6f8844f843b        centos              "echo hello world"       3 hours ago         Exited (0) 3 hours ago                         reverent_yalow

例:只查所有镜像的id

[root@docker ~]# docker ps -a -q

edfdd26e20da

f6f8844f843b

查看所有运行容器的id只要去掉-a参数即可。

3.2.5、容器删除

可以使用docker rm 来删除一个出于终止状态的容器。

例:删除

[root@docker ~]# docker ps -a

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS               NAMES

f6f8844f843b        centos              "echo hello world"       4 hours ago         Exited (0) 4 hours ago                         reverent_yalow

[root@docker ~]# docker rm reverent_yalow

reverent_yalow

[root@docker ~]# docker ps -a

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS               NAMES

cd9cf2398630        centos              "while true ;echo hel"   4 hours ago         Created                                        high_mclean

如果删除一个正在运行中的容器,可以添加-f 参数。Docker会发送SIGKLL信号给容器。

清理所有出于终止状态的容器,可以配合刚才我们展示的docker ps -a -q。用docker rm $(docker ps -a -q)

例:删除所有终止状态的容器

[root@docker ~]# docker ps -a

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS                     PORTS               NAMES

cd9cf2398630        centos              "while true ;echo hel"   4 hours ago         Created                                        high_mclean

[root@docker ~]# docker rm $(docker ps -a -q)

cd9cf2398630

[root@docker ~]# docker ps -a

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

c761cee8863f        docker.io/centos    "/bin/bash"         7 hours ago         Up About an hour                        mycentos

这里还有一个测试时好用的参数

docker run --rm   [选项] [镜像名称] [命令]

使用

例:创建一个测试容器,退出后自动给删除

root@docker ~]# docker ps -a

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

c761cee8863f        docker.io/centos    "/bin/bash"         7 hours ago         Up About an hour                        mycentos

[root@docker ~]# docker run --rm -it  --name ceshi centos /bin/bash

[root@e392d10516b0 /]# exit

[root@docker ~]# docker ps -a

CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES

c761cee8863f        docker.io/centos    "/bin/bash"         7 hours ago         Up About an hour                        mycentos

 

 

 

进入容器和网络访问

 

随机映射:

docker run -d -P httpd  类似我们公司买了一台路由器在上面做了一个端口映射帮我们上网一样

 

其实上面的命令的原理结果在iptables里可以看出来:

[root@linux-node1 ~]# iptables -t nat -vnL

 

我们可以进容器实例里面去看一下实际情况:

 

 

 

可以很明显的看到确实是映射正确的

访问日志:

[root@linux-node1 ~]# docker logs cc41ebe12346

 

测试效果:

 

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

 

查看映射:

 

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

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

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

 

 

 

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

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

 

 

 Docker数据管理

 

Docker数据资源存储管理原理图 (分层设计存储的)

 

 

如果想要数据持久化永久保存就引入下面概念:(docker理念其实是停了就停了,没有持久保存这一说)  其实数据卷类似光盘一样,挂载就行了,其实也不是很好管理,因为如果你有几百个镜像,就得挂载几百个目录

 

 

4.1 挂载数据卷

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

docker run -d --name volume-test1  -v /data httpd

创建一个名字是volume-test1,以httpd系统为基础镜像的容器,它的主机名是httpd,把这个容器的/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 指定容器挂载到宿主的固定目录生产常用的

docker run -d --name volume-test2  -v /mnt/test/:/data nginx



 测试:


 

 

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

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

 

4.2 数据卷容器类似nfs 差不多  其实生产不用

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

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

 

 

可以看到它就访问到了centos容器挂载的内容了

 

  1.  手动构建Docker镜像,生产不常用,一般都是自动化

获取镜像id

 

[root@linux-node1 ~]# docker kill $(docker ps -a -q)  干掉所有运行的容器

[root@linux-node1 ~]# docker rm $(docker ps -a -q)  删除所有容器 这种命令生产绝对不能用

容器是运行起来叫容器 镜像是镜像这两个是不同概念的(禁止的状态)

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

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

①  docker pull centos

②  docker run –it –name  nginx-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;

⑥  下载nginx的tar包,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镜像了

 

我们可以这个镜像创建一个容器:

 

注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: 卢烈楚 

#Base images

FROM centos

 

#MAINTAINER  维护者

MAINTAINER luliechu   983765387@qq.com

 

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

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

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

 

 

#commands  干什么

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.gz和nginx-1.10.1.tar.gz拷贝到与Dockerfile的同级目录下。

④  构建镜像,docker build -t mynginx:v2 /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限制配额

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

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

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

比如有两个容器,A容器的cpu配额是1024,B容器的cpu配额是512,那么启动这两个容器时A容器占用66%的cpu,B容器占用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。

注:这里的宿主机是相对于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命令查看),每启动一个容器都会创建一个桥接接口

 

ip add li

 

 

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

Iptables -t nat -Ln

 

 


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 registry。registry的默认运行端口是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镜像

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

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

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

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

 

 

 

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

 

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

 

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

 

 

重新push镜像:

 

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

 

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了。

10生产构建docker镜像核心思想,生产案例演示

架构架构  分层设计

 

docker生产实践

 

系统层

运行环境层  tomcat  php等

 

应用服务层    shopping  按业务来分  (配置文件代码)

写好的结构如下:写好之后再提交

 

 

 

 

案例写一个纯系统镜像:

# Docker for CentOS

 

#Base image

FROM centos

 

#Who

MAINTAINER luliechu 983765387@qq.com

 

#EPEL

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

 

#Base pkg

RUN yum install -y wget mysql-devel supervisor git redis tree net-tools sudo psmisc && yum clean all

 

 

写一个带ssh的纯系统镜像:

# Docker for CentOS

 

#Base image

FROM centos

 

#Who

MAINTAINER luliechu 983765387@qq.com

 

#EPEL

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

 

#Base pkg

RUN yum install -y openssh-clients openssl-devel openssh-server wget mysql-devel supervisor git redis tree net-tools sudo psmisc && yum clean all

 

# For SSHD

 

 

RUN ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key

RUN ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key

RUN echo "root:123" | chpasswd

 

 

在系统上写一个基于纯系统上python环境

#Base image

FROM test/centos:base

 

#Maintainer

MAINTAINER luliechu  9837653887@qq.com

 

# Python env

RUN yum install -y python-devel python-pip supervisor

 

# Upgrade pip

RUN pip install --upgrade pip

 

 

在带ssh系统上写一个基于上搭建python环境

#Base image

FROM test/centos-ssh

 

#Maintainer

MAINTAINER luliechu 983765387@qq.com

# Python env

RUN yum install -y python-devel python-pip supervisor

 

# Upgrade pip

RUN pip install --upgrade pip

 

 

部署应用

 

 

Dockerfile 如下:

Base image

FROM test/python-ssh

 

#Maintainer

MAINTAINER luliechu 983765387@qq.com

 

# Add www user

RUN useradd -s /sbin/nologin -M www

 

# ADD file

ADD app.py /opt/app.py

ADD requirements.txt /opt/

ADD supervisord.conf /etc/supervisord.conf

ADD app-supervisor.ini /etc/supervisord.d/

 

# pip

RUN /usr/bin/pip2.7 install -r /opt/requirements.txt

 

# Port

EXPOSE 22 5000

 

#CMD

CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"]