docker是一种虚拟化的技术,相对于虚拟机更加轻量级。

虚拟化技术

虚拟化是一种资源管理技术,将计算机的各种实体资源比如:cpu、内存、网络、存储等进行抽象,转换呈现出来,来解决实体结构间不可切割的问题,使用户对资源重新组装来提高资源使用率。它的目标通常是为了在一台主机上运行多个系统或应用,从而提高系统资源利用率,降低成本,方便管理和容灾备份等。

基于硬件的虚拟化

传统虚拟化技术是在硬件资源级别的虚拟化,需要有虚拟机管理程序(Hypervisor)和虚拟机操作系统(vm),进行的是操作系统级别的隔离。

基于软件的虚拟化

Docker直接建立在操作系统上虚拟化,直接复用本地操作系统,更加轻量级,通过操作系统的cgroup和namespace进行进程级别的隔离。

为什么是docker

docker成功之处就在于它推出了镜像打包技术,支持了标准化的交付,搞容器虚拟化技术的很多,而虚拟化技术概念更是在50年前就出现了,但是最后docker出现一统天下,是因为它推出了镜像打包技术,使得容器在部署,扩缩容,删除都变得简单,轻量级,是整个云平台的基础。

相继推动了devops的发展,devops核心是敏捷开发,标准交付,快速部署。

docker优势

1、敏捷开发、持续集成,标准交付
    1、开发、测试和生产的环境一致性。也就是环境标准化和版本控制,通过镜像技术将应用与应用所依赖的运行环境打包,进行版本化管理,一旦故障可以快速回滚,相对于虚拟机镜像,docker压缩和备份速度更快,镜像启动如启动一个进程一样
    2、松散耦合、分布式、弹性、解放的微服务:应用程序被分解成较小的独立部分,能够快速迭代
    3、镜像仓库,方便管理。

2、快速部署
    1、云和操作系统分发的可移植性:可在 Ubuntu、RHEL、CoreOS、本地、Google Kubernetes Engine 和其他任何地方运行,也就是跨平台跨环境。
    2、轻量级

3、提高资源利用率
    1、资源隔离:可预测的应用程序性能。
    2、资源利用:高效率和高密度。

docker缺点

1、安全问题
2、大规模情况下的管理问题:部署,升级回滚,扩缩容,自愈等。
3、网络问题:服务发现和负载均衡

这些正是k8s解决的问题。

docker安装

在安装之前需要确保linux的内核版本在3.10.X以上,没有话需要升级内核,我在我的虚拟机的上升级内核了可以参考centos内核升级

docker是以linux容器化技术(LXC)为基础的,所以在linux上体验最好,通常使用root用户安装

yum

初始

1、docker放在epel镜像源中,所以需要先添加镜像源

yum install -y http://mirrors.yun-idc.com/epel/6/x86_64/epel-release-6-8.noarch.rpm

加载完需要修改源文件,将baseurl放开,将mirrorlist注释掉才能链接上。

2、docker与一个系统自带的程序重名,所以修改为docker-io

sudo yum install -y docker-io

3、启动

service docker start  或者docker -d

加入开机启动项:chkconfig docker on

过程中可能有一个device-mapper-libs需要升级,这边用yum源直接升级 yum upgrade device-mapper-libs没有用,需要现在最新的安装包进行安装

2017.2.13

在centos 7上使用无法链接到对应到镜像,重官网上获取新到docker源

sudo yum-config-manager --add-repo https://docs.docker.com/engine/installation/linux/repo_files/centos/docker.repo

然后使用yum makecache加载后重新安装

sudo yum install -y docker-engine

在次过程中,有一个组件需要升级,rpm包需要手动下载

rpm -e selinux-policy-targeted-3.13.1-60.el7_2.9.noarch
rpm -ivh selinux-policy-targeted-3.13.1-190.fc24.noarch.rpm --nodeps

然后启动docker

systmctl start docker

到此docker就安装好了,启动docker服务就可以对docker进行操作了。

2017.3.21

docker重3.1之后开始改变命名,分为ce和ee企业版。这个都是在官方网站上的产品,在github上都迁至moby项目下,这边安装更新

OS requirements

To install Docker, you need the 64-bit version of CentOS 7.

Uninstall old versions

sudo yum remove docker \
                docker-common \
                container-selinux \
                docker-selinux \
                docker-engine

Install yum-utils, which provides the yum-config-manager utility:

$ sudo yum install -y yum-utils

add repo并且生效加载

$ sudo yum-config-manager \
    --add-repo \
        https://download.docker.com/linux/centos/docker-ce.repo

$ sudo yum-config-manager --disable docker-ce-edge

$ sudo yum makecache fast

install

sudo yum install docker-ce

$ sudo systemctl start docker
$ sudo docker run hello-world

rpm

新版的也有对应的rpm可以安装。

所以可以重官网下载rpm来安装,我们通过官网提供的yum源来下载rpm包,然后安装

用于离线安装

https://download.docker.com/linux/centos/7/x86_64/stable/Packages/

到这个地址下载对应的rpm包

安装需要的依赖包也要下载

http://mirrors.163.com/centos/7/os/x86_64/Packages/ 下载8个依赖,正常就是centos自身所带的包,如果机器解决了centos的包就不用下载了

audit-libs-python-2.7.6-3.el7.x86_64.rpm

checkpolicy-2.5-4.el7.x86_64.rpm

libcgroup-0.41-13.el7.x86_64.rpm

libseccomp-2.3.1-3.el7.x86_64.rpm

libsemanage-python-2.5-8.el7.x86_64.rpm

policycoreutils-python-2.5-17.1.el7.x86_64.rpm

python-IPy-0.75-6.el7.noarch.rpm

setools-libs-3.3.8-1.1.el7.x86_64.rpm

这个是必然需要下载的

1、在 http://rpm.pbone.net/index.php3?stat=3&limit=1&srodzaj=1&dl=40&search=container-selinux&field[]=1&field[]=2 下载container-selinux-2.9-4.el7.noarch.rpm

包都可以在这个 http://rpm.pbone.net/index.php3 来下载

2、pigz-2.3.4-1.el7.x86_64.rpm

启动

systemctl start docker

docker使用

docker容器三大核心:镜像,容器和仓库

镜像是docker引擎只读的一块模版,包含文件系统,容器是基于镜像创建的一个实例,在镜像上加了一个可写层,实现了对镜像对起停等各种操作。

镜像

镜像:是docker的基础,包含app所需要的lib库以及app应用。

  • 下载:docker pull name[:tag] 不指定tag默认取最新版本laster。

  • 创建容器:docker run -t -i 镜像版本 /bin/bash(可执行文件) 启动一个bash终端,-t表示一个伪终端并绑定在容器的标准输入中,-i则让容器标准输入保持打开 守护态运行 -d -p XX:XXX 为映射端口,将docker容器端口XX映射到宿主机的xxX端口

  • 查看镜像信息:docker images

  • 为镜像新增标签:docker tag 镜像名 标签名

  • 获取镜像的详细信息:docker inspect images-id 同一个镜像的image-id是一样的 返回一个json格式的信息,具体到那一类信息用-f参数

  • 搜索镜像:docker search -s n n星以上的镜像 关键字

  • 删除镜像:docker rmi 标签/image-id 当该镜像创建容器正在运行,则无法删除,当然可以使用-f 强制删除,但是不建议使用。其实最原始的就是docker images rm,后来简化为docker rmi,原来的依然可用。

  • 创建镜像:

    1. 基于已有镜像创建 docker commit [option] container [repository[:tag]]

      option:-a 作者信息 -m 提交信息 -p 提交时暂停容器运行

      例如:docker commit -a “jcy” -m “redisconfigload” 01758f83ddb2 redisconfigload

      还可以基于正在运行的容器,比如做了一些操作,保存为一个镜像

      $ docker exec -it 4ddf4638572d /bin/sh
      # 在容器内部新建了一个文件
      root@4ddf4638572d:/app# touch test.txt
      root@4ddf4638572d:/app# exit
      
      #将这个新建的文件提交到镜像中保存
      $ docker commit 4ddf4638572d geektime/helloworld:v2
      
    2. 基于本地模板的导出导入 docker export/import

      例如:

       docker export 7691a814370e > ubuntu.tar.gz
      cat ubuntu.tar.gz | docker import - ubuntu:14.04
      
    3. 基于dockerfile

      dockerfile一种文本格式的配置文件,由一行行命名组成,支持#开头的注释,主要组成如下:
      
      基础镜像信息 FROM <image>:<tag>  第一条必须是这个命令,可以基于多个镜像,也可以基于空镜像scratch
      
      维护者信息   MAINTAINER <name>
      
      镜像操作指令  RUN <command> 类似于/bin/sh -c  RUN ["executable","param1","param2"] 使用exec来执行
      
      容器启动时执行的指令
      CMD ["executable","param1","param2"]使用exec来执行,运行一个可执行的文件并提供参数
      CMD command param1 param2   也可以是一个shell脚本,者就是一个带参数执行的命令bin/sh中执行,提供给需要交互的用户
      CMD ["param1","param2"]  给ENTRYPOINT提供默认参数
      CMD命令只执行一次,多条也会被覆盖,只执行最后一条,而且会被docker run指定的运行命令所覆盖。
      
      EXPOSE 让docker容器暴露出端口来
      
      ENV key value 指定环境变量
      ARG指令定义了用户可以在编译时或者运行时传递的变量,如使用如下命令:--build-arg <varname>=<value>
      
      
      ADD COPY都是复制,ADD会对tar包进行解压,COPY不会,COPY可以自动创建不存在的目录。
      
      ENTRYPOINT ["executable","param1","param2"]使用exec来执行
      ENTRYPOINT command param1 param2  shell执行,一样是容器启动后执行的,不会被cmd覆盖,同样只有一条生效。多条的情况下最后一条有效。
      
      VOLUME ["/data"] 创造挂载点
      
      WORKDIR  指定容器的工作目录。
      

      最后用docker build 来创建镜像 -t指定镜像的标签信息 -f dockerfile的路径 .

      比如:

      docker build -t fabric8-console:2.2.199 -f /root/f8/f8-console/fabric8-console-2.2.199/Dockerfile .
      

      每一步都会生成一个块,对应的有一个唯一哈希值标志,下一次再进行打包的时候可以直接用这个缓存的块,可见镜像是由块组成的,dockerfile步骤越多块越多,镜像就越大,所以最后是基于空镜像,将文件系统的相关环境设置好打成tar包,然后用ADD加入,减少后面run执行的步骤,减小镜像的大小。 上面的哈希是根据大小来生成的,如果大小一样,哈希值会一样,不过这个很少出现,如果出现可以加上参数–no-cache=true不使用缓存。

      我们一般都是使用dockerfile来制作镜像。

  • 存储镜像:docker save 将镜像存储为本地的文件

    docker save busybox > busybox.tar
    
    docker save --output busybox.tar busybox
    
        $ sudo docker save -o fedora-all.tar fedora
        $ sudo docker save -o fedora-latest.tar fedora:latest
    
    docker save 1316871b180b -o /root/dockerfile/loggermanager1.0.tar
    
  • 载入镜像:docker load 将本地镜像文件加载为本地镜像库的镜像

    docker load < path/xxx.tar
    
  • 上传镜像:docker push name[:tag]

    先用docker tag打标签,然后这个标签上传到默认的dockerhub中,当然也可以上传到私有仓库。例如:

    在dockerhub上注册了user

    docker tag test:latest user/test:latest
    docker push user/test:latest
    

    私有库的搭建以及上传管理在下面详细讲解。

  • 镜像下载

    Docker默认拉取镜像是从这里拉取,拉取的速度让人。。。,所以是配置国内镜像源,拉取速度十分惊人,可以自己去阿里云申请一个免费的加速器,我们一般会自己免费申请一下阿里云的镜像加速器,其实就是换了阿里的镜像源。

    针对Docker客户端版本大于 1.10.0 的用户

    您可以通过修改daemon配置文件/etc/docker/daemon.json来使用加速器

    sudo mkdir -p /etc/docker
    sudo tee /etc/docker/daemon.json <<-'EOF'
    {
      "registry-mirrors": ["https://qzre5v92.mirror.aliyuncs.com"]
    }
    EOF
    sudo systemctl daemon-reload
    sudo systemctl restart docker
    

容器

容器:在镜像上加一个隔离层,相当于一个个运行的实例,可以用docker ps -a 来查看当前所有的启停实例。

  • 创建: docker create

  • 启动:docker start/stop 合二为一 docker run

  • 创建容器:docker run -t -i .. /bin/bash 启动一个bash终端,-t表示一个伪终端并绑定在容器的标准输入中,-i则让容器标准输入保持打开 守护态运行-d,退出用exit或者ctrl+d,-v挂载卷,-e传递环境变量,-p映射端口,是通过iptables实现的,可以用iptables-save查看。当然还可以通过参数对资源进行限制。

    • 也可以使用docker run centos /bin/echo ‘hello world’,这样就类似在本地执行echo ‘hello world’
    • docker run 主要查看本地是否有镜像,没有则去dockerhub上下载,dcokerhub官方网站不支持直接下载镜像,注册后只能有自己的私有仓库,还是不能下载镜像
    • 利用镜像创建并启动一个容器
    • 分配一个文件系统,给只读的镜像外层加一个可写层
    • 从宿主机的网桥接口中桥接一个虚拟接口到容器
    • 配置一个ip
    • 执行用户制定的程序
    • 执行完终止容器
  • 进入容器:

    • docker attach name 这个是docker自带的命令,但是在多个终端一起链接到该容器的时候,他们是同步的,当其中一个出现问题时,其他的也会一样出现该问题

    • docker exec -ti id /bin/bash 这个也是docker自带的,在docker1.3之后,它在容器中启动来一个bash,但是并不是所有的容器都是在linux系统上建立起来的,并不一定能启动bash

      docker exec 是怎么做到进入容器里的呢?实际上,Linux Namespace 创建的隔离空间虽然看不见摸不着,但一个进程的 Namespace 信息在宿主机上是确确实实存在的,并且是以一个文件的方式存在。比如,通过如下指令,你可以看到当前正在运行的 Docker 容器的进程号(PID)是 25686:

      $ docker inspect --format '{{ .State.Pid }}'  4ddf4638572d
      25686
      

      这时,你可以通过查看宿主机的 proc 文件,看到这个 25686 进程的所有 Namespace 对应的文件:

      $ ls -l  /proc/25686/ns
      total 0
      lrwxrwxrwx 1 root root 0 Aug 13 14:05 cgroup -> cgroup:[4026531835]
      lrwxrwxrwx 1 root root 0 Aug 13 14:05 ipc -> ipc:[4026532278]
      lrwxrwxrwx 1 root root 0 Aug 13 14:05 mnt -> mnt:[4026532276]
      lrwxrwxrwx 1 root root 0 Aug 13 14:05 net -> net:[4026532281]
      lrwxrwxrwx 1 root root 0 Aug 13 14:05 pid -> pid:[4026532279]
      lrwxrwxrwx 1 root root 0 Aug 13 14:05 pid_for_children -> pid:[4026532279]
      lrwxrwxrwx 1 root root 0 Aug 13 14:05 user -> user:[4026531837]
      lrwxrwxrwx 1 root root 0 Aug 13 14:05 uts -> uts:[4026532277]
      

      可以看到,一个进程的每种 Linux Namespace,都在它对应的 /proc/[进程号]/ns 下有一个对应的虚拟文件,并且链接到一个真实的 Namespace 文件上。有了这样一个可以“hold 住”所有 Linux Namespace 的文件,我们就可以对 Namespace 做一些很有意义事情了,比如:加入到一个已经存在的 Namespace 当中。这也就意味着:一个进程,可以选择加入到某个进程已有的 Namespace 当中,从而达到“进入”这个进程所在容器的目的,这正是 docker exec 的实现原理。而这个操作所依赖的,乃是一个名叫 setns() 的 Linux 系统调用。

      通过 open() 系统调用打开了指定的 Namespace 文件,并把这个文件的描述符 fd 交给 setns() 使用。它一共接收两个参数,第一个参数是 argv[1],即当前进程要加入的 Namespace 文件的路径,比如 /proc/25686/ns/net;而第二个参数,则是你要在这个 Namespace 里运行的进程,比如 /bin/bash。一个进程加入到了另一个 Namespace 当中了。

    • 可以用工具nsenter,是一个需要安装的工具。

  • 容器资源限制参数 dockerfile的路径

    • -m 1024m –memory-swap=1024m # 限制内存最大使用(bug:超过后进程被杀死)

    • –cpuset-cpus=“0,1” # 限制容器使用CPU

  • docker容器随系统自启参数

    docker run –restart=always redis

    • no – 默认值,如果容器挂掉不自动重启

    • on-failure – 当容器以非 0 码退出时重启容器 同时可接受一个可选的最大重启次数参数 (e.g. on-failure:5).

    • always – 不管退出码是多少都要重启

  • 删除:docker rm

    -f 强制删除 -l 删除链接 -v删除挂载卷

  • 导入和导出:docker export/import 将容器导出为tar文件,将文件导入为镜像,docker load差不多

  • docker logs id 记录容器内的操作

    • docker logs id
  • docker容器和主机进行拷贝

    1. 重docker容器内拷贝到主机上

      [root@oegw1 soft]# docker ps
      CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
      8d418a7b6021        postgres            "/docker-entrypoint.   7 hours ago         Up 7 hours                              test1
      [root@oegw1 soft]# docker exec -t -i 8d418a7b6021 /bin/bash
      root@oegw1:/var/lib/postgresql# pwd
      /var/lib/postgresql
      root@oegw1:/var/lib/postgresql# ls
      data
      root@oegw1:/var/lib/postgresql# exit
      exit
      [root@oegw1 soft]# docker cp 8d418a7b6021:/var/lib/postgresql/data /opt/soft/
      完成拷贝
      
    2. 重主机拷贝到docker容器中

      • 挂载,也即是主机和docker容器共享一个目录

        1. 在创建容器到时候用 -v XXX:XXX 来挂载

          [root@pdapp18 etc]# docker run -it -v /opt/inkscope/etc:/mnt centos /bin/bash
          [root@bd91c6b79e87 mnt]# ll
          total 4
          -rw-r--r--. 1 root root 1323 May 23  2016 inkscope.conf
          [root@bd91c6b79e87 mnt]# exit
          [root@pdapp18 etc]# pwd
          /opt/inkscope/etc
          [root@pdapp18 etc]# l
          总用量 4
          -rw-r--r--. 1 root root 1323 5月  23 2016 inkscope.conf
          
        2. 动态挂载

          后续完成

        3. docker还提供来一个数据卷的高级用法

          数据卷:“其实就是一个正常的容器,专门用来提供数据卷供其它容器挂载的”。感觉像是由一个容器定义的一个数据挂载信息。其他的容器启动可以直接挂载数据卷容器中定义的挂载信息。

          看示例:

          docker run -v /root:/root  --name test centos /bin/bash
          创建一个普通的容器。用--name给他指定了一个名(不指定的话会生成一个随机的名子)。
          
          然后其他容器就可以使用--volumes-from来引用这个数据卷,就可以让当前容器中的/root目录和本机的/root的进行共享
          docker run -it --volumes-from test centos /bin/bash
          
      • 首先查看这个容器的id

        docker inspect -f '{{.Id}}' container-id返回容器的id
        

        实际上本机的/var/lib/docker/container/contianer-id/和docker容器的根目录/是一致的,所以可以直接操作这个目录相当于操作容器的根目录,实现共享。但是我试验没有实现,等有时间再看看什么原因。

仓库

仓库:存放镜像文件的

最大docker官方公共仓库:docker hub,国内:docker pool

官方的仓库镜像一般就是基础镜像,单个单词命名,而username/镜像名这个一般是某个用户上传的镜像

默认是重docker hub上下载,如果需要重其他的镜像仓库下载则需要加前缀。

当然也可以创建私有仓库。主要是通过docker registry这个python开源项目进行创建,registry2之后已经重构用go来开发,目前的registry的版本是2.6,但是有着很多的问题,现在已经有对应的容器镜像了,当然也可以通过源码进行安装。当然也可以使用集成的仓库的harbor等管理工具。

搭建私有库:

首先下载官方提供的的镜像并且创建一个容器

docker run -d -p 5000:5000 --restart=always --name registry registry:2

我们可以docker ps看一下镜像已经启动,可以使用crul http://ip:5000 看看网络是否通,本地机器和容器之间的通信也需要iptables,iptables-services来进行通信。

[root@pdapp20 ~]# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
98de3ec23d75        registry:2          "/entrypoint.sh /e..."   16 hours ago        Up 16 hours         0.0.0.0:5000->5000/tcp   registry""

可以通过iptables-save来保存现有的规则同时也能查看,不过这个只需要安装好iptables,iptables-services并启动着就可以自动加入通信的规则。然后检查容器与主机之间是否是通的

1、/usr/sbin/sestatus -v      ##如果SELinux status参数为enabled即为开启状态
SELinux status:                 enabled
2、getenforce                 ##也可以用这个命令检查
关闭SELinux:
1、临时关闭(不用重启机器):
setenforce 0                  ##设置SELinux 成为permissive模式
                              ##setenforce 1 设置SELinux 成为enforcing模式
2、修改配置文件需要重启机器:
    修改/etc/selinux/config 文件
    将SELINUX=enforcing改为SELINUX=disabled
    重启机器即可

这个时候网络应该是通的了,然后我们tag一个自己的镜像

docker pull ubuntu && docker tag ubuntu localhost:5000/ubuntu

然后上传

docker push localhost:5000/ubuntu

可以通过http://localhost:5000/v2/_catalog (在v1版本的时候是v1/search,现在在v2版本中已经不使用)来查看私有仓库的镜像,并到每一个镜像中去查看该镜像的具体信息。

[root@pdapp20 ~]# curl http://localhost:5000/v2/_catalog
{"repositories":["hello-world","ubuntu"]}
[root@pdapp20 ~]# curl http://localhost:5000/v2/tags/list
404 page not found
[root@pdapp20 ~]# curl http://localhost:5000/v2/ubuntu/tags/list
{"name":"ubuntu","tags":["latest"]}
[root@pdapp20 ~]# curl http://localhost:5000/v2/hello-world/tags/list
{"name":"hello-world","tags":["latest"]}

然后我们删除本地的镜像,重自己的私有库来下载

[root@pdapp20 ~]# docker rmi localhost:5000/hello-world
Untagged: localhost:5000/hello-world:latest
Untagged: localhost:5000/hello-world@sha256:2075ac87b043415d35bb6351b4a59df19b8ad154e578f7048335feeb02d0f759
[root@pdapp20 ~]# docker images
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
registry            2                   047218491f8c        2 weeks ago         33.2 MB
ubuntu              latest              0ef2e08ed3fa        3 weeks ago         130 MB
hello-world         latest              48b5124b2768        2 months ago        1.84 kB
centos              latest              67591570dd29        3 months ago        192 MB
[root@pdapp20 ~]# docker pull localhost:5000/hello-world
Using default tag: latest
latest: Pulling from hello-world
Digest: sha256:2075ac87b043415d35bb6351b4a59df19b8ad154e578f7048335feeb02d0f759
Status: Downloaded newer image for localhost:5000/hello-world:latest

当然私有仓库可以进行加密认证。

私有库的镜像的默认存储路径是/tmp/registry,可以通过启动参数-v进行修改,比如下面的例子将上传的镜像放到 /opt/data/registry 目录

docker run -d -p 5000:5000 -v /opt/data/registry:/tmp/registry registry

也可以讲镜像存储到云服务器上去,都有对应的配置

还可以制定配置文件-v /home/user/registry-conf:/registry-conf

错误解决

Private registry push fail: server gave HTTP response to HTTPS client

1.Create or modify /etc/docker/daemon.json
{ "insecure-registries":["myregistry.example.com:5000"] }
2.Restart docker daemon
sudo service docker restart

其他

目前harbor已经在私有库一统天下了,vmware开源,国人开发,界面友好,使用简单,各大企业都是使用这个私有库组件Harbor

数据和网络

数据

数据管理实现数据的共享和备份。核心就是-v参数。

共享

1、数据卷

数据卷是一个可供一个或多个容器使用的特殊目录,它绕过UFS,可以提供很多有用的特性:

  • 数据卷可以在容器之间共享和重用
  • 对数据卷的修改会立马生效
  • 对数据卷的更新,不会影响镜像
  • 卷会一直存在,直到没有容器使用

简单说来,卷就是将宿主机中的某个目录,mount到容器中,这样,在容器中此目录下的修改,即便容器关闭,数据也会保留下来,供宿主机和其他容器访问。

数据卷的使用,类似于 Linux 下对目录或文件进行 mount。

主要是下面的使用方式

  • 在运行容器的时候,在Docker中创建一个数据卷

    docker run -dti -v /data centos
    #在docker中会有/data目录,这个目录不归属于层级文件系统
    ls /data -d
    /data
    

    由于你并没有显示声明宿主机目录,那么 Docker 就会默认在宿主机上创建一个临时目录 /var/lib/docker/volumes/[VOLUME_ID]/_data,然后把它挂载到容器的 /data 目录上。

  • 将宿主机的一个目录,挂在到容器里,这种方式,数据可以保存在宿主机中

    #例如将宿主机的/var/data挂载到容器中的/data
    docker run -tdi -v /var/data:/data centos
    
  • 挂载单个文件到容器中

    docker run -tdi ~/dbback.tar.gz:/dbback.tar.gz centos
    

2、数据卷容器

数据卷容器的作用是,其中挂载的数据卷,可以被使用它的容器,共同使用。也就是多个容器之间可以同时使用这个数据卷,容器对他的写入内容,在其他容器也能看到。

实例

#创建一个包含数据卷的容器供其他容器使用,这个容器并不需要一直开启
docker run -tdi -v /data --name data_s centos
#创建两个容器,使用这个数据卷容器
docker run -ti --volumes-from data_s  --name web1 centos
docker run -ti --volumes-from data_s  --name web2 centos
#此时这两个容器,都可以共同读写/data目录了
#如果需要将数据同步到宿主机的目录中,则创建数据卷容器的时候,选择挂载宿主机的目录,如:
docker run -tdi -v /data:/data --name data_s centos

备份

docker run -d -volumes-from data -v $(pwd):/backup  ubuntu
tar -zcvf /backup/buckup.tar.gz /data

这样可以将容器数据卷data打包成backup.tar.gz,然后放到容器的backup目录下和本地主机的当前目录共享。实现备份。

数据恢复就是将压缩包解压到共享目录,然后放到数据卷的容器中去。

网络

核心参数-p和-P,这边只是简单的映射使用,需要了解实现就要看核心的网络原理

1、容器到主机:

端口的映射可以制定主机端口,可以多次制定,可以指定所有的,可以通过docker port来查看当前容器的端口。

2、容器到容器:

通过–link来在容器之间建立一个安全到通道,避免暴露在外

docker run --rm -it --name web2 --link db:db training/webapp /bin/bash

root@5845d10a2bf5:/opt/webapp# cat /etc/hosts
127.0.0.1    localhost
::1    localhost ip6-localhost ip6-loopback
fe00::0    ip6-localnet
ff00::0    ip6-mcastprefix
ff02::1    ip6-allnodes
ff02::2    ip6-allrouters
172.17.0.3    db c6cd414f08d4   -------这边在web的容器里面有db的容器的主机配置
172.17.0.5    5845d10a2bf5
root@5845d10a2bf5:/opt/webapp# apt-get install -yqq inetutils-ping
E: Failed to fetch http://archive.ubuntu.com/ubuntu/pool/universe/i/inetutils/inetutils-ping_1.9.2-1_amd64.deb  Could not resolve 'archive.ubuntu.com'

E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?
root@5845d10a2bf5:/opt/webapp# ping db
PING db (172.17.0.3) 56(84) bytes of data.
64 bytes from db (172.17.0.3): icmp_seq=1 ttl=64 time=0.204 ms
64 bytes from db (172.17.0.3): icmp_seq=2 ttl=64 time=0.106 ms
64 bytes from db (172.17.0.3): icmp_seq=3 ttl=64 time=0.097 ms
64 bytes from db (172.17.0.3): icmp_seq=4 ttl=64 time=0.102 ms

----网络是通的,说明两个容器之间建立来一个安全的通道。

Docker集群通信:

  • 自定义网桥
  • 使用adbasssdor容器—目前已经有实现的容器集群管理方案,例如k8s

docker实践

busybox

busybox是一个集成一百多个常用的linux命令的工具箱,经常使用的echo,cat,mount,grep等等都在这个里面,是linux系统的瑞士军刀。

docker pull busybox
docker run -it busybox

就可以在这个镜像中使用各个命令了。

ubuntu/centos

docker pull centos

CoreOS

CoreOS是基于docker发行的linux的版本

支持ssh的镜像

首先下载镜像并创建容器,在容器中安装openssh-server,并启动该服务,然后在根目录下写一个脚本run.sh,来启动ssh,然后用docker commit来打包一个新的镜像。

然后可以用这个镜像创建容器启动服务就可以通过ssh来链接这个容器了

docker run -p 10022:22 -d sshd:centos /run.sh

ssh 宿主机 -p 10022 就可以登录到容器内

编排

docker Compose

Compose,你可以在一个文件中定义一个多容器应用,然后使用一条命令来启动你的应用,完成一切准备工作。

使用Docker Compose,不再需要使用shell脚本来启动容器。在配置文件中,所有的容器通过services来定义,然后使用docker-compose脚本来启动,停止和重启应用,和应用中的服务以及所有依赖服务的容器。

build 构建或重建服务
help 命令帮助
kill 杀掉容器
logs 显示容器的输出内容
port 打印绑定的开放端口
ps 显示容器
pull 拉取服务镜像
restart 重启服务
rm 删除停止的容器
run 运行一个一次性命令
scale 设置服务的容器数目
start 开启服务
stop 停止服务
up 创建并启动容器

安装

1、在线下载

curl -L https://github.com/docker/compose/releases/download/1.4.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod  x /usr/local/bin/docker-compose

2、离线github上有对应的二进制包。

3、通过配置yml文件来部署。

docker swarm

和k8s是同一个级别的编程工具,目前已经放弃,k8s已经一家独大。

常规使用

1、docker删除所有的容器

docker ps -a | awk '{print $1}' | xargs docker rm

2、解决SELinux is not supported with the overlay2 graph driver on this kernel.

屏蔽#OPTIONS='--selinux-enabled --log-driver=journald --signature-verification=false'
加DOCKER_OPTS="--storage-driver=devicemapper"

3、镜像源

1、docker有官方的中国区加速器了!

–registry-mirror=https://registry.docker-cn.com

2、网易163 docker镜像

$ sudo echo "DOCKER_OPTS=\"--registry-mirror=http://hub-mirror.c.163.com\"" >> /etc/default/docker
$ service docker restart

一般来说,网易的猪肉比市场上的猪肉好吃。但从我的体验来看,有时会pull失败的情况出现,并且重试不好使。

3、ustc的镜像

ustc是老牌的linux镜像服务提供者了,还在遥远的ubuntu 5.04版本的时候就在用。之前在blog里有提到可以用ustc的docker仓库镜像,使用方法参考ustc docker 镜像使用帮助,你要是懒得看,可以两条命令搞定(ubuntu亲测):

$ sudo echo "DOCKER_OPTS=\"--registry-mirror=https://docker.mirrors.ustc.edu.cn\"" >> /etc/default/docker
$ sudo service docker restart

ustc的docker镜像速度不错,一直用的挺happy。但是今天发现不好使了,可能跟这件事有关系吧,今天尝试去pull ubuntu,非常慢,应该是直接去docker hub上去拉了,基本没有加速效果。

据说收费了,用网易的吧!

4、daocloud

DaoCloud也提供了docker加速器,但是跟ustc不同,需要用户注册后才能使用,并且每月限制流量10GB。linux上使用比较简单,一条命令搞定:

curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://{your_id}.m.daocloud.io

实际改的是/usr/lib/systemd/system/docker.service,加了个–registry-mirror参数,:

ExecStart=/usr/bin/docker-current daemon --registry-mirror=http://{your_id}.m.daocloud.io\

设置后,需要重新加载配置&重启:

systemctl enable docker; systemctl daemon-reload ; systemctl restart docker

但是!今天使用DaoCloud的docker加速器体验非常差,加速效果基本没感觉,果断放弃。

5、alicloud

阿里云也提供了docker加速器,不过比ustc更麻烦:不光要注册为阿里云的用户,还得加入开发者平台。不过捏着鼻子做完这些以后,它的服务还真是不错,基本1MB/s的pull速度(部分原因可能是因为我也在杭州吧)。配置方法跟daocloud类似,也是开通加速器以后给一个url。

我直接去改/usr/lib/systemd/system/docker.service了:

ExecStart=/usr/bin/docker-current daemon --registry-mirror=https://{your_id}.mirror.aliyuncs.com\

重新加载配置&重启:

systemctl enable docker; systemctl daemon-reload ; systemctl restart docker

pull的时候还是显示docker.io,但速度一点都不docker.io。

4、分层编译–docker版本要在17.06之后

FROM golang:1.9-alpine3.6 as builder

ENV PILOT_DIR /go/src/github.com/AliyunContainerService/log-pilot
ARG GOOS=linux
ARG GOARCH=amd64
RUN set -ex \
    && apk add --no-cache make git
WORKDIR $PILOT_DIR
COPY . $PILOT_DIR
RUN go install

FROM alpine:3.6

ENV FILEBEAT_VERSION=6.1.1-3
RUN apk update && \
    apk add ca-certificates && \
    apk add wget && \
    update-ca-certificates && \
    rm -rf /var/cache/apk/*

COPY --from=builder /go/bin/log-pilot /pilot/pilot
COPY assets/filebeat/filebeat.tpl /pilot/

WORKDIR /pilot/
ENTRYPOINT ["/pilot/pilot"]

上面一个用于编译,然后把编译好的结果copy到我最终的镜像中去

5、docker跨平台

docker跨平台是一个重大价值,但是个人觉得是基于docker引擎之上的,类似于java都是跑在jvm上,而跨平台是不同版本的jvm,docker也是一样,也是镜像跑在不同版本的docker上实现跨平台,但是不同的是,docker不是基于原有的系统上创建虚拟机,然后运行docker,docker都是原生的基于内核的,当然一开始不同版本还是基于虚拟机的,现在实现了,这是跨平台的优势之一。

6、docker stats -a 查看容器资源消耗情况

7、CICD

首先企业中的开发人员开发完成app之后,将代码推送代码管理仓库Github中,,这个时候Github探测到仓库中代码的变更,自动触发Jenkins编译应用,之后通过Dockerfile来打包成一个镜像,镜像可以直接推送到镜像存储中保存,上面的流程实现了持续集成,另外Jenkins可以在测试域上启动应用,进行测试,验证完成之后,触发上线应用的流程,实现CD流程。

具体可以参考CDCI

原理

docker实现的原理

发展

docker目前发展并不是太好,k8s新版本开始支持containerd,大有取代docker的趋势。