Docker基础教程

Docker与微服务

基础篇

Docker简介

Docker是基于Go语言实现的云开源项目。Docker之所以发展如此迅速,也是因为它对此给出了一个标准化的解决方案:系统平滑移植,容器虚拟化技术

Docker基础教程

Docker的主要目标是“Build, Ship and Run Any App, Anywhere”,也就是通过对应用组件的封装、分发、部署、运行等生命周期的管理,使用户的APP(可以是一个WEB应用或数据库应用等等)及其运行环境能够做到“一次镜像,处处运行”。

Docker基础教程

VM vs Docker

  • 传统虚拟机技术是虚拟出一套硬件后,在其上运行一个完整操作系统,在该系统上再运行所需应用进程;
  • 容器内的应用进程直接运行于宿主的内核,容器内没有自己的内核且也没有进行硬件虚拟。因此容器要比传统虚拟机更为轻便。
  • 每个容器之间互相隔离,每个容器有自己的文件系统 ,容器之间进程不会相互影响,能区分计算资源。

开发/运维(DevOps)

一次构建、随处运行

  • 更快速的应用交付和部署
    传统的应用开发完成后,需要提供一堆安装程序和配置说明文档,安装部署后需根据配置文档进行繁杂的配置才能正常运行。Docker化之后只需要交付少量容器镜像文件,在正式生产环境加载镜像并运行即可,应用安装配置在镜像里已经内置好,大大节省部署配置和测试验证时间。
  • 更便捷的升级和扩缩容
    随着微服务架构和Docker的发展,大量的应用会通过微服务方式架构,应用的开发构建将变成搭乐高积木一样,每个Docker容器将变成一块“积木”,应用的升级将变得非常容易。当现有的容器不足以支撑业务处理时,可通过镜像运行新的容器进行快速扩容,使应用系统的扩容从原先的天级变成分钟级甚至秒级。
  • 更简单的系统运维
    应用容器化运行后,生产环境运行的应用可与开发、测试环境的应用高度一致,容器会将应用程序相关的环境和状态完全封装起来,不会因为底层基础架构和操作系统的不一致性给应用带来影响,产生新的BUG。当出现程序异常时,也可以通过测试环境的相同容器进行快速定位和修复。
  • 更高效的计算资源利用
    Docker是内核级虚拟化,其不像传统的虚拟化技术一样需要额外的Hypervisor支持,所以在一台物理机上可以运行很多个容器实例,可大大提升物理服务器的CPU和内存的利用率。

前提条件

目前,CentOS 仅发行版本中的内核支持 Docker。Docker 运行在CentOS 7 (64-bit)上,要求系统为64位、Linux系统内核版本为 3.8以上。

查看内核:

  • uname -r
  • cat /etc/redhat-release

Docker的基本组成

  • 镜像 image
    Docker 镜像(Image)就是一个只读的模板。镜像可以用来创建 Docker 容器,一个镜像可以创建很多容器。
  • 容器 container
    Docker 利用容器(Container)独立运行的一个或一组应用,应用程序或服务运行在容器里面,容器就类似于一个虚拟化的运行环境,容器是用镜像创建的运行实例。(可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。)
  • 仓库 repository
    仓库(Repository)是集中存放镜像文件的场所。(Docker公司提供的官方registry被称为Docker Hub:https://hub.docker.com/

Docker安装

https://docs.docker.com/engine/install/centos/

  1. 确定你是CentOS7及以上版本
  2. 卸载旧版本
  3. yum安装gcc相关:yum -y install gcc gcc-c++
  4. 安装需要的软件包:yum install -y yum-utils
  5. 设置stable镜像仓库 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
  6. 更新yum软件包索引:yum makecache fast
  7. 安装DOCKER CE:yum -y install docker-ce docker-ce-cli containerd.io
  8. 启动docker:systemctl start docker
  9. 测试:docker version;docker run hello-world
  10. 卸载:systemctl stop docker ;yum remove docker-ce docker-ce-cli containerd.io;rm -rf /var/lib/docker;rm -rf /var/lib/containerd

阿里云镜像加速

https://promotion.aliyun.com/ntms/act/kubernetes.html

容器镜像服务-镜像加速器

Docker为什么比VM虚拟机快

  • docker有着比虚拟机更少的抽象层
    由于docker不需要Hypervisor(虚拟机)实现硬件资源虚拟化,运行在docker容器上的程序直接使用的都是实际物理机的硬件资源。因此在CPU、内存利用率上docker将会在效率上有明显优势。
  • docker利用的是宿主机的内核,而不需要加载操作系统OS内核
    当新建一个容器时,docker不需要和虚拟机一样重新加载一个操作系统内核。进而避免引寻、加载操作系统内核返回等比较费时费资源的过程,当新建一个虚拟机时,虚拟机软件需要加载OS,返回新建过程是分钟级别的。而docker由于直接利用宿主机的操作系统,则省略了返回过程,因此新建一个docker容器只需要几秒钟。

Docker基础教程

常用命令

帮助类命令

  • 启动:systemctl start docker
  • 停止:systemctl stop docker
  • 重启:systemctl restart docker
  • 查看状态:systemctl status docker
  • 开机启动:systemctl enable docker
  • 查看概要信息:docker info
  • 帮助文档:docker --help
  • 具体命令帮助:docker 具体命令 --help

镜像命令

  • docker images

    • 本地镜像列表(repository:镜像的仓库源,tag:镜像标签版本号,image id:镜像ID,created:镜像创建时间,size:镜像大小)
    • 参数:-a:列出本地所有的镜像(含历史映像层);-q:只显示镜像ID
  • docker search [options] xxx

    • 搜索镜像
    • 参数:--limit:只列出N个镜像,默认25个
  • docker pull xx[:tag]

    • 下载镜像,无tag则代表最新镜像,同:docker pull xx:latest
  • docker system df

    • 查看镜像/容器/数据卷所占的空间
  • docker rmi xx镜像ID

    • 删除单个镜像:docker rmi -f 镜像ID
    • 删除多个:docker rmi -f 镜像1名:TAG 镜像2名:TAG
    • 删除全部:docker rmi -f $(docker images -qa)

容器命令

拉取ubuntu镜像:docker pull ubuntu

  1. 新建+启动容器:docker run [options] image [command] [arg...]
  • options

    • --name="容器新名字"
    • -d 后台运行容器并返回容器ID,即启动守护式容器
    • -i 以交互模式运行容器,通常与 -t 同时使用
    • -t 为容器重新分配一个伪终端,-it 即启动交互式容器
    • -P 随机映射端口
    • -p 指定端口映射

Docker基础教程

  1. docker ps [options]
  • 列出当前所有正在运行的容器
  • 参数:

    • -a:列出当前所有正在运行的容器+历史上运行过的
    • -l:显示最近创建的容器
    • -n:显示最近n个创建的容器
    • -q:静默模式,只显示容器编号
  1. 退出容器
  • exit:容器停止
  • ctrl+p+q:容器不停止
  1. 启动已停止运行的容器
  • docker start 容器ID或容器名
  1. 重启容器
  • docker restart 容器ID或容器名
  1. 停止容器
  • docker stop 容器ID或容器名
  1. 强制停止容器
  • docker kill 容器ID或容器名
  1. 删除已停止的容器
  • docker rm 容器ID
  • 批量删除

    • docker rm -f $(docker ps -a -q)
    • docker ps -a -q | xargs docker rm
  1. 查看容器日志
  • docker logs 容器ID
  1. 查看容器内运行的进程
  • docker top 容器ID
  1. 查看容器内部细节
  • docker inspect 容器ID
  1. 进入正在运行的容器并以命令行交互
  • [推荐] docker exec -it 容器ID bashShell
  • 重新进入docker attach 容器ID

    attach 直接进入容器启动命令的终端,不会启动新的进程
    用exit退出,会导致容器的停止。

    exec 是在容器中打开新的终端,并且可以启动新的进程
    用exit退出,不会导致容器的停止。

  1. 从容器内拷贝文件到主机上
  • docker cp 容器ID:容器内路径 目的主机路径
  1. 导入和导出容器
  • docker export 容器ID > 文件名.tar(export 导出容器的内容留作为一个tar归档文件[对应import命令];import 从tar包中的内容创建一个新的文件系统再导入为镜像[对应export])
  • cat 文件名.tar | docker import - 镜像用户/镜像名:镜像版本号
  1. commit
  • docker commit 提交容器副本使之成为 一个新的镜像
  • docker commit -m="提交的描述信息" -a="作者" 容器ID 要创建的目标镜像名:[标签名]
  • 示例ubuntu安装vim:

    • docker pull ubuntu
    • docker run -it ubuntu /bin/bash
    • apt-get update #更新包管理器
    • apt-get install vim
    • exit
    • docker commit -m="add vim" -a="sensen" 345c8360dc47 sensen/myubuntu:1.1
    • docker images
Docker容器后台运行,就必须有一个前台进程。
容器运行的命令如果不是那些一直挂起的命令(比如运行top,tail),就是会自动退出的。

虚悬镜像

仓库名、标签都是none的镜像(dangling image)

Docker镜像

一种轻量级、可执行的独立软件包,它包含运行某个软件所需的所有内容,我们把应用程序和配置依赖打包好形成一个可交付的运行环境(包括代码、运行时需要的库、环境变量和配置文件等),这个打包好的运行环境就是image镜像文件。只有通过这个镜像文件才能生成Docker容器实例。

镜像分层

UnionFS 联合文件系统

UnionFS(联合文件系统):Union文件系统(UnionFS)是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。Union 文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。

Docker镜像加载原理

docker的镜像实际上由一层一层的文件系统组成,这种层级的文件系统UnionFS。

bootfs(boot file system)主要包含bootloader和kernel, bootloader主要是引导加载kernel, Linux刚启动时会加载bootfs文件系统,在Docker镜像的最底层是引导文件系统bootfs。这一层与我们典型的Linux/Unix系统是一样的,包含boot加载器和内核。当boot加载完成之后整个内核就都在内存中了,此时内存的使用权已由bootfs转交给内核,此时系统也会卸载bootfs。

rootfs (root file system) ,在bootfs之上。包含的就是典型 Linux 系统中的 /dev, /proc, /bin, /etc 等标准目录和文件。rootfs就是各种不同的操作系统发行版,比如Ubuntu,Centos等等。

centos镜像只有200M左右

对于一个精简的OS,rootfs可以很小,只需要包括最基本的命令、工具和程序库就可以了,因为底层直接用Host的kernel,自己只需要提供 rootfs 就行了。由此可见对于不同的linux发行版, bootfs基本是一致的, rootfs会有差别, 因此不同的发行版可以公用bootfs。

镜像分层优点

镜像分层最大的一个好处就是共享资源,方便复制迁移,就是为了复用。

比如说有多个镜像都从相同的 base 镜像构建而来,那么 Docker Host 只需在磁盘上保存一份 base 镜像;
同时内存中也只需加载一份 base 镜像,就可以为所有容器服务了。而且镜像的每一层都可以被共享。

Docker镜像层都是只读的,容器层是可写的。

当容器启动时,一个新的可写层被加载到镜像的顶部。这一层通常被称作“容器层”,“容器层”之下的都叫“镜像层”。

所有对容器的改动 - 无论添加、删除、还是修改文件都只会发生在容器层中。只有容器层是可写的,容器层下面的所有镜像层都是只读的。

本地镜像发布到阿里云

Docker基础教程

https://promotion.aliyun.com/ntms/act/kubernetes.html

  1. 进入:容器镜像服务
  2. 选择个人实例
  3. 命名空间-设置命名空间
  4. 镜像仓库-创建镜像仓库
  5. 推送到阿里云:docker login --username=xx registry.cn-hangzhou.aliyuncs.com docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/r1989/myubuntu:[镜像版本号] docker push registry.cn-hangzhou.aliyuncs.com/r1989/myubuntu:[镜像版本号]

本地镜像发布到私有库

Docker Registry是官方提供的工具,可以用于构建私有镜像仓库。

  1. 下载镜像docker registry:docker pull registry
  2. 运行私有库Registry,相当于本地有个私有Docker hub

    • docker run -d -p 5000:5000 -v /sensen/myregistry/:/tmp/registry --privileged=true registry(默认情况,仓库被创建在容器的/var/lib/registry目录下)
  3. 案例演示创建一个新镜像,ubuntu安装ifconfig命令
  4. curl验证私服库上有什么镜像

  5. 将新镜像myubuntu:1.2修改符合私服规范的Tag

    • 按照公式: docker tag 镜像:Tag Host:Port/Repository:Tag
    • docker tag myubuntu:1.2 192.168.xx.xx:5000/myubuntu:1.2
  6. 修改配置文件使之支持http

    • vim /etc/docker/daemon.json
    • {
      "registry-mirrors": ["https://xxx.mirror.aliyuncs.com"],
      "insecure-registries": ["192.168.xx.xx:5000"]
      }
    • docker默认不允许http方式推送镜像,通过配置选项来取消这个限制。 修改完后如果不生效,建议重启docker
  7. push推送到私服库

    • docker push 192.168.xx.xx:5000/myubuntu:1.2
  8. curl验证私服库上有什么镜像2
  9. pull到本地并运行

Docker容器数据卷

Docker挂载主机目录访问如果出现:cannot open directory .: Permission denied

解决办法:在挂载目录后多加一个--privileged=true参数即可

使用该参数,container内的root拥有真正的root权限,否则,container内的root只是外部的一个普通用户权限。

卷就是目录或文件,存在于一个或多个容器中,由docker挂载到容器,但不属于联合文件系统,因此能够绕过Union File System提供一些用于持续存储或共享数据的特性:
卷的设计目的就是数据的持久化,完全独立于容器的生存周期,因此Docker不会在容器删除时删除其挂载的数据卷。

类似redis中的rdb和aof文件,将docker容器内的数据保存进宿主机的磁盘中。

docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录 镜像名

特点:

  • 数据卷可在容器之间共享或重用数据
  • 卷中的更改可以直接实时生效
  • 数据卷中的更改不会包含在镜像的更新中
  • 数据卷的生命周期一直持续到没有容器使用它为止

宿主vs容器之间映射添加容器卷

docker run -it --name=myu1 --privileged=true -v /tmp/myubuntu:/tmp/dockerData ubuntu /bin/bash

查看是否挂载成功:docker inspect

Docker基础教程

测试主机或docker修改数据、docker停止后主机修改数据,重启docker数据同步。

读写规则映射添加说明

docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:rw 镜像名(默认为rw)

docker run -it --privileged=true -v /宿主机绝对路径目录:/容器内目录:ro 镜像名(容器实例内部被限制,只能读取不能写)

卷的继承和共享

  1. docker run -it --privileged=true -v /mydocker/u:/tmp --name u1 ubuntu
  2. docker run -it --privileged=true --volumes-from u1 --name u2 ubuntu

Docker常规安装简介

步骤:

  1. 搜索镜像
  2. 拉取镜像
  3. 查看镜像
  4. 启动镜像
  5. 停止容器
  6. 移除容器

示例:

文档地址:https://hub-stage.docker.com/_/mysql

  • docker search mysql
  • docker pull mysql:8.0
  • 新建mysql容器实例:docker run -d -p 3307:3306 --privileged=true -v /docker/mysql8/log:/var/log/mysql -v /docker/mysql8/data:/var/lib/mysql -v /docker/mysql8/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql8 mysql:8.0
  • 新建my.cnf:vim /docker/mysql8/conf/my.cnf
  • 重新启动mysql容器实例再重新进入并查看字符编码:docker restart mysql8;docker exec -it mysql8 bash;mysql -uroot -p;show variables like "character%";
  • 建库表 create database db01;use db01;create table user(id int, name varchar(20));insert into user values(1, '森森');select * from user;
  • 删除容器重新创建测试数据库仍存在

高级篇

Docker复杂安装

mysql主从复制

  1. 新建主服务器实例3307

    • docker run -d -p 3307:3306 --privileged=true -v /docker/mysql-master/log:/var/log/mysql -v /docker/mysql-master/data:/var/lib/mysql -v /docker/mysql-master/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql-master mysql:8.0
  2. 新增my.cnf

    • vim /docker/mysql-master/conf/my.cnf

      [mysqld]
      ## 设置server_id,同一局域网中需要唯一
      server_id=101 
      ## 指定不需要同步的数据库名称
      binlog-ignore-db=mysql  
      ## 开启二进制日志功能
      log-bin=mall-mysql-bin  
      ## 设置二进制日志使用内存大小(事务)
      binlog_cache_size=1M  
      ## 设置使用的二进制日志格式(mixed,statement,row)
      binlog_format=mixed  
      ## 二进制日志过期清理时间。默认值为0,表示不自动清理。
      expire_logs_days=7  
      ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
      ## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
      slave_skip_errors=1062
      
  3. 修改后重启:docker restart mysql-master
  4. 进入master容器:docker exec -it mysql-master /bin/bash
  5. master容器实例内创建数据同步用户

    • CREATE USER 'slave'@'%' IDENTIFIED BY '123456';
    • GRANT REPLICATION SLAVE, REPLICATION CLIENT ON . TO 'slave'@'%';
  6. 新建从服务器容器实例3308
  • docker run -d -p 3308:3306 --privileged=true -v /docker/mysql-slave/log:/var/log/mysql -v /docker/mysql-slave/data:/var/lib/mysql -v /docker/mysql-slave/conf:/etc/mysql/conf.d -e MYSQL_ROOT_PASSWORD=123456 --name mysql-slave mysql:8.0
  1. 进入/docker/mysql-slave/conf目录下新建my.cnf

    [mysqld]
    ## 设置server_id,同一局域网中需要唯一
    server_id=102
    ## 指定不需要同步的数据库名称
    binlog-ignore-db=mysql  
    ## 开启二进制日志功能,以备Slave作为其它数据库实例的Master时使用
    log-bin=mall-mysql-slave1-bin  
    ## 设置二进制日志使用内存大小(事务)
    binlog_cache_size=1M  
    ## 设置使用的二进制日志格式(mixed,statement,row)
    binlog_format=mixed  
    ## 二进制日志过期清理时间。默认值为0,表示不自动清理。
    expire_logs_days=7  
    ## 跳过主从复制中遇到的所有错误或指定类型的错误,避免slave端复制中断。
    ## 如:1062错误是指一些主键重复,1032错误是因为主从数据库数据不一致
    slave_skip_errors=1062  
    ## relay_log配置中继日志
    relay_log=mall-mysql-relay-bin  
    ## log_slave_updates表示slave将复制事件写进自己的二进制日志
    log_slave_updates=1  
    ## slave设置为只读(具有super权限的用户除外)
    read_only=1
    
  2. 修改完配置后重启slave实例:docker restart mysql-slave
  3. 在主数据库中查看主从同步状态:show master status;
  4. 进入mysql-slave容器
  5. 在从数据库中配置主从复制

    • change master to master_host='127.0.0.1', master_user='slave', master_password='123456', master_port=3307, master_log_file='mall-mysql-bin.000003', master_log_pos=712, master_connect_retry=30;
    • master_host:主数据库的IP地址;
      master_port:主数据库的运行端口;
      master_user:在主数据库创建的用于同步数据的用户账号;
      master_password:在主数据库创建的用于同步数据的用户密码;
      master_log_file:指定从数据库要复制数据的日志文件,通过查看主数据的状态,获取File参数;
      master_log_pos:指定从数据库从哪个位置开始复制数据,通过查看主数据的状态,获取Position参数;
      master_connect_retry:连接失败重试的时间间隔,单位为秒。
  6. 查看从服务器状态:show slave status \G;
  7. 在从数据库中开启主从同步:start slave;
  8. 查看从数据库状态发现已经同步:show slave status \G;
  9. 主从复制测试

DockerFile解析

DockerFile是用来构建Docker镜像的文本文件,是由一条条构建镜像所需的指令和参数构成的脚本。

https://docs.docker.com/engine/reference/builder/

构建步骤

  • 编写dockerfile文件
  • docker build 命令构建镜像
  • docker run 依镜像运行容器实例

dockerfile内容基础知识

  • 每条保留字指令都必须为大写字母且后面要跟随至少一个参数
  • 指令按照从上到下,顺序执行
  • 表示注释

  • 每条指令都会创建一个新的镜像层并对镜像进行提交

执行dockerfile流程

  • docker从基础镜像运行一个容器
  • 执行一条指令并对容器作出修改
  • 执行类似docker commit的操作提交一个新的镜像层
  • docker再基于刚提交的镜像运行一个新容器
  • 执行dockerfile中的下一条指令直到所有指令都执行完成
参考:https://github.com/docker-library/tomcat

Dockerfile常用保留字指令

  • FROM:基础镜像,当前新镜像是基于哪个镜像的,指定一个已经存在的镜像作为模板,第一条必须是from
  • MAINTAINER:镜像维护者的姓名和邮箱地址
  • RUN

    • 容器构建时需要运行的命令
    • shell格式:RUN yum -y install vim
    • exec格式:RUN ['可执行文件', '参数1', '参数2']
    • RUN是在 docker build时运行
  • EXPOSE:当前容器对外暴露出的端口
  • WORKDIR:指定在创建容器后,终端默认登陆的进来工作目录,一个落脚点
  • USER:指定该镜像以什么样的用户去执行,如果都不指定,默认是root
  • ENV:用来在构建镜像过程中设置环境变量
  • ADD:将宿主机目录下的文件拷贝进镜像且会自动处理URL和解压tar压缩包
  • COPY:类似ADD,拷贝文件和目录到镜像中。将从构建上下文目录中 <源路径> 的文件/目录复制到新的一层的镜像内的 <目标路径> 位置。

    • COPY src dest
    • COPY ["src", "dest"]
    • <src源路径>:源文件或者源目录
    • <dest目标路径>:容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。
  • VOLUME:容器数据卷,用于数据保存和持久化工作
  • CMD:指定容器启动后的要干的事情

    • Dockerfile 中可以有多个 CMD 指令,但只有最后一个生效,CMD 会被 docker run 之后的参数替换
    • CMD是在docker run 时运行;RUN指令是在docker build时运行
  • ENTRYPOINT:也是用来指定一个容器启动时要运行的命令

    • 类似于 CMD 指令,但是ENTRYPOINT不会被docker run后面的命令覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序
    • 格式:ENTRYPOINT ["executeable", 'param1', 'param2', '...']
    • 在执行docker run的时候可以指定 ENTRYPOINT 运行所需的参数。
    • 如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。

自定义Docker示例

  • 编写Dokcerfile文件

    FROM centos
    MAINTAINER zzyy<zzyybs@126.com>
     
    ENV MYPATH /usr/local
    WORKDIR $MYPATH
     
    #安装vim编辑器
    RUN yum -y install vim
    #安装ifconfig命令查看网络IP
    RUN yum -y install net-tools
    #安装java8及lib库
    RUN yum -y install glibc.i686
    RUN mkdir /usr/local/java
    #ADD 是相对路径jar,把jdk-8u171-linux-x64.tar.gz添加到容器中,安装包必须要和Dockerfile文件在同一位置
    ADD jdk-8u171-linux-x64.tar.gz /usr/local/java/
    #配置java环境变量
    ENV JAVA_HOME /usr/local/java/jdk1.8.0_171
    ENV JRE_HOME $JAVA_HOME/jre
    ENV CLASSPATH $JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib:$CLASSPATH
    ENV PATH $JAVA_HOME/bin:$PATH
     
    EXPOSE 80
     
    CMD echo $MYPATH
    CMD echo "success--------------ok"
    CMD /bin/bash
  • 构建:docker build -t 新镜像名字:TAG .

虚悬镜像

仓库名、标签都是none的镜像,俗称:dangling image

如Dockerfile:

FROM ubuntu
CMD echo "action is success"
docker build .

查看:docker image ls -f dangling=true

删除:docker image prune

Docker微服务

Docker网络

docker不启动时,默认的网络情况:ens33、lo、virbr0

在CentOS7的安装过程中如果有选择相关虚拟化的的服务安装系统后,启动网卡时会发现有一个以网桥连接的私网地址的virbr0网卡(virbr0网卡:它还有一个固定的默认IP地址192.168.122.1),是做虚拟机网桥的使用的,其作用是为连接其上的虚机网卡提供 NAT访问外网的功能。

docker启动后会增加名为docker0的虚拟网桥

查看docker网络模式:docker network ls

基本命令

docker network --help

查看网络:docker network ls

查看网络源数据:docker network inspect xx网络名字

删除网络:docker network rm xx网络名字

创建网络:docker network create xx网络名字

用途

  • 容器间的互联和通信,以及端口映射
  • 容器IP变动时可以通过服务名直接网络通信而不受影响

网络模式

  • bridge模式:使用--network bridge指定,默认使用docker0
  • host模式:使用--network host指定
  • none模式:使用--network none指定
  • container模式:使用--network container:NAME或者容器ID指定

容器实例内默认网络IP生产规则

  1. 启动两个容器实例

    • docker run -it --name u1 ubuntu bash
    • docker run -it --name u2 ubuntu bash
  2. docker inspect 容器ID或名字查看IP地址
  3. 关闭u2,新建u3,查看IP变化:docker inspect u3 | tail -n 20

结论:docker容器内的IP是有可能会发生改变的

bridge

Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机和容器之间可以通过网桥相互通信。

1 Docker使用Linux桥接,在宿主机虚拟一个Docker容器网桥(docker0),Docker启动一个容器时会根据Docker网桥的网段分配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就能够通过容器的Container-IP直接通信。

2 docker run 的时候,没有指定network的话默认使用的网桥模式就是bridge,使用的就是docker0。在宿主机ifconfig,就可以看到docker0和自己create的network(后面讲)eth0,eth1,eth2……代表网卡一,网卡二,网卡三……,lo代表127.0.0.1,即localhost,inet addr用来表示网卡的IP地址

3 网桥docker0创建一对对等虚拟设备接口一个叫veth,另一个叫eth0,成对匹配。
3.1 整个宿主机的网桥模式都是docker0,类似一个交换机有一堆接口,每个接口叫veth,在本地主机和容器内分别创建一个虚拟接口,并让他们彼此联通(这样一对接口叫veth pair);
3.2 每个容器实例内部也有一块网卡,每个接口叫eth0;
3.3 docker0上面的每个veth匹配某个容器实例内部的eth0,两两配对,一一匹配。
通过上述,将宿主机上的所有容器都连接到这个内部网络上,两个容器在同一个网络下,会从这个网关下各自拿到分配的ip,此时两个容器的网络是互通的。

Docker基础教程

host

直接使用宿主机的 IP 地址与外界进行通信,不再需要额外进行NAT 转换。

容器将不会获得一个独立的Network Namespace, 而是和宿主机共用一个Network Namespace。容器将不会虚拟出自己的网卡而是使用宿主机的IP和端口。

Docker基础教程

docker run -d --network host --name tomcat83 billygoo/tomcat8-jdk8 (不可指定端口)

none

在none模式下,并不为Docker容器进行任何网络配置。 也就是说,这个Docker容器没有网卡、IP、路由等信息,只有一个lo。需要我们自己为Docker容器添加网卡、配置IP等。

docker run -d -p 8084:8080 --network none --name tomcat84 billygoo/tomcat8-jdk8

container

新建的容器和已经存在的一个容器共享一个网络ip配置而不是和宿主机共享。新创建的容器不会创建自己的网卡,配置自己的IP,而是和一个指定的容器共享IP、端口范围等。同样,两个容器除了网络方面,其他的如文件系统、进程列表等还是隔离的。

Docker基础教程

Alpine Linux 是一款独立的、非商业的通用 Linux 发行版,专为追求安全性、简单性和资源效率的用户而设计。 可能很多人没听说过这个 Linux 发行版本,但是经常用 Docker 的朋友可能都用过,因为他小,简单,安全而著称,所以作为基础镜像是非常好的一个选择,可谓是麻雀虽小但五脏俱全,镜像非常小巧,不到 6M的大小,所以特别适合容器打包。
  1. docker run -it --name alpine1 alpine /bin/sh
  2. docker run -it --network container:alpine1 --name alpine2 alpine /bin/sh
  3. ip addr 验证共用搭桥
  4. 关闭alpine1,则alpine2网络消失

自定义网络

自定义桥接网络,自定义网络默认使用的是桥接网络bridge。

  1. docker network create ss_network
  2. docker network ls
  3. 新建容器加入上一步新建的自定义网络

    • docker run -d -p 8081:8080 --network zzyy_network --name tomcat81 billygoo/tomcat8-jdk8
    • docker run -d -p 8082:8080 --network zzyy_network --name tomcat82 billygoo/tomcat8-jdk8
  4. 互相ping测试

    • docker exec -it tomcat81 bash
    • ping tomcat82

结论:

自定义网络本身就维护好了主机名和IP的关系(IP和域名都能通);

Docker平台架构图解

从其架构和运行流程来看,Docker 是一个 C/S 模式的架构,后端是一个松耦合架构,众多模块各司其职。

Docker 运行的基本流程为:

  1. 用户是使用 Docker Client 与 Docker Daemon 建立通信,并发送请求给后者。
  2. Docker Daemon 作为 Docker 架构中的主体部分,首先提供 Docker Server 的功能使其可以接受 Docker Client 的请求。
  3. Docker Engine 执行 Docker 内部的一系列工作,每一项工作都是以一个 Job 的形式的存在。
  4. Job 的运行过程中,当需要容器镜像时,则从 Docker Registry 中下载镜像,并通过镜像管理驱动 Graph driver将下载镜像以Graph的形式存储。
  5. 当需要为 Docker 创建网络环境时,通过网络管理驱动 Network driver 创建并配置 Docker 容器网络环境。
  6. 当需要限制 Docker 容器运行资源或执行用户指令等操作时,则通过 Execdriver 来完成。
  7. Libcontainer是一项独立的容器管理包,Network driver以及Exec driver都是通过Libcontainer来实现具体对容器进行的操作。

Docker基础教程

Docker-compose容器编排

https://docs.docker.com/compose/compose-file/compose-file-v3/

Docker-Compose是Docker官方的开源项目,负责实现对Docker容器集群的快速编排。

Compose 是 Docker 公司推出的一个工具软件,可以管理多个 Docker 容器组成一个应用。你需要定义一个 YAML 格式的配置文件docker-compose.yml,写好多个容器之间的调用关系。然后,只要一个命令,就能同时启动/关闭这些容器。

安装流程

  1. curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
  2. chmod +x /usr/local/bin/docker-compose
  3. docker-compose --version

Compose核心概念

文件:docker-compose.yml

两要素:

  • 服务service:一个个应用容器实例,比如订单微服务、库存微服务、mysql容器、nginx容器或者redis容器。
  • 工程project:由一组关联的应用容器组成的一个完整业务单元,在 docker-compose.yml 文件中定义。

使用步骤:

  1. 编写Dockerfile定义各个微服务应用并构建出对应的镜像文件
  2. 使用 docker-compose.yml 定义一个完整业务单元,安排好整体应用中的各个容器服务。
  3. 最后,执行docker-compose up命令 来启动并运行整个应用程序,完成一键部署上线

compose常用命令

docker-compose -h  # 查看帮助
docker-compose up # 启动所有docker-compose服务
docker-compose up -d # 启动所有docker-compose服务并后台运行
docker-compose down # 停止并删除容器、网络、卷、镜像。
docker-compose exec yml里面的服务id  # 进入容器实例内部  docker-compose exec docker-compose.yml文件中写的服务id /bin/bash
docker-compose ps # 展示当前docker-compose编排过的运行的所有容器
docker-compose top # 展示当前docker-compose编排过的容器进程
 
docker-compose logs  yml里面的服务id # 查看容器输出日志
docker-compose config     # 检查配置
docker-compose config -q  # 检查配置,有问题才有输出
docker-compose restart   # 重启服务
docker-compose start     # 启动服务
docker-compose stop      # 停止服务

docker-compose.yml示例:

version: "3"
 
services:
  microService:
    image: zzyy_docker:1.6
    container_name: ms01
    ports:
      - "6001:6001"
    volumes:
      - /app/microService:/data
    networks: 
      - atguigu_net 
    depends_on: 
      - redis
      - mysql
 
  redis:
    image: redis:6.0.8
    ports:
      - "6379:6379"
    volumes:
      - /app/redis/redis.conf:/etc/redis/redis.conf
      - /app/redis/data:/data
    networks: 
      - atguigu_net
    command: redis-server /etc/redis/redis.conf
 
  mysql:
    image: mysql:5.7
    environment:
      MYSQL_ROOT_PASSWORD: '123456'
      MYSQL_ALLOW_EMPTY_PASSWORD: 'no'
      MYSQL_DATABASE: 'db2021'
      MYSQL_USER: 'zzyy'
      MYSQL_PASSWORD: 'zzyy123'
    ports:
       - "3306:3306"
    volumes:
       - /app/mysql/db:/var/lib/mysql
       - /app/mysql/conf/my.cnf:/etc/my.cnf
       - /app/mysql/init:/docker-entrypoint-initdb.d
    networks:
      - atguigu_net
    command: --default-authentication-plugin=mysql_native_password #解决外部无法访问
 
networks: 
   atguigu_net: 
 

轻量级可视化工具Portainer

Portainer 是一款轻量级的应用,它提供了图形化界面,用于方便地管理Docker环境,包括单机环境和集群环境。

https://www.portainer.io/

https://docs.portainer.io/v/ce-2.9/start/install/server/docker/linux

安装:docker run -d -p 8000:8000 -p 9000:9000 --name portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer

访问:http://x.x.x.x:9000/

容器监控之CAdvisor+InfluxDB+Granfana

通过docker stats命令可以很方便的看到当前宿主机上所有容器的CPU,内存以及网络流量等数据,一般小公司够用了。但是,docker stats统计结果只能是当前宿主机的全部容器,数据资料是实时的,没有地方存储、没有健康指标过线预警等功能。

CAdvisor监控收集+InfluxDB存储数据+Granfana展示图表

Docker基础教程

Docker基础教程

Docker基础教程

version: '3.1'
 
volumes:
  grafana_data: {}
 
services:
 influxdb:
  image: tutum/influxdb:0.9
  restart: always
  environment:
    - PRE_CREATE_DB=cadvisor
  ports:
    - "8083:8083"
    - "8086:8086"
  volumes:
    - ./data/influxdb:/data
 
 cadvisor:
  image: google/cadvisor
  links:
    - influxdb:influxsrv
  command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxsrv:8086
  restart: always
  ports:
    - "8080:8080"
  volumes:
    - /:/rootfs:ro
    - /var/run:/var/run:rw
    - /sys:/sys:ro
    - /var/lib/docker/:/var/lib/docker:ro
 
 grafana:
  user: "104"
  image: grafana/grafana
  user: "104"
  restart: always
  links:
    - influxdb:influxsrv
  ports:
    - "3000:3000"
  volumes:
    - grafana_data:/var/lib/grafana
  environment:
    - HTTP_USER=admin
    - HTTP_PASS=admin
    - INFLUXDB_HOST=influxsrv
    - INFLUXDB_PORT=8086
    - INFLUXDB_NAME=cadvisor
    - INFLUXDB_USER=root
    - INFLUXDB_PASS=root

Tags: docker

添加新评论