Docker
1.Docker入门
1.1 Docker概述
- 什么是Docker - Docker是一个基于容器化技术,针对开发、运维进行应用程序的开发、运行和部署的平台 - 使用Linux容器进行应用程序的部署,就称作容器化 - 容器化并不是一种新的理念,它主要是用于降低应用程序在不同环境上的部署难度 - 避免了由于开发人员与运维人员在软件环境上的差异性,出现各种软件部署的问题 
- 虚拟化 vs 容器化 - 虚拟化   - 容器化   - 特性 - 容器 - 虚拟机 - 启动 - 秒级 - 分钟级 - 性能 - 接近原生 - 弱于 - 空间使用 - 一般为MB - 一般为GB - 系统支持量 - 单机支持上千个 
- Docker的优势 - 更快速的交付和部署
- 更高效的虚拟化
- 更轻松的迁移和扩展
- 更简单的管理
 
- Docker的劣势 - 不支持异构系统的虚拟化,原生Docker只能运行在linux系统上
 
- Docker能干什么 - 简化配置
- 代码流水线管理
- 提高开发效率
- 隔离应用
- 整合服务器
- 调试能力
- 多租户
- 快速部署
 
1.2 Docker架构

Docker组成
- docker server/daemon
- docker client
- docker registry/仓库
1.3 Docker与Kubernetes
 
2.Docker安装
Docker目前推出的版本分为两种:
- 社区版/Community Edition (CE)
- 企业版/Enterprise Edition (EE)

支持平台



2.1 linux环境下的安装
- 移除老版本Docker - 1 - sudo yum remove docker docker-common docker-selinux docker-engine 
- 安装Docker依赖包 - 1 - sudo yum install -y yum-utils device-mapper-persistent-data lvm2 
- 配置Docker仓库源 - 1 
 2- sudo yum-config-manager --add-repo \ 
 https://download.docker.com/linux/centos/docker-ce.repo
- 安装Docker CE - 1 - sudo yum install -y docker-ce 
- 启动Docker 
- ```shell 
 sudo systemctl start docker- 1 
 2
 3
 4
 5
 查看Docker版本
 ```shell
 docker version
- 测试 - 1 - sudo docker run hello-world 
2.2 Docker核心概念
Docker是一个提供了开发、打包、运行app的平台
它把app和底层的基础设施隔离开来
 
Docker Engine
 
Docker Engine的组成
- 后台进程(dockerd)
- Rest API Server
- CLI接口
2.3 Docker底层技术实现
- Namespaces - 用于隔离pid、net、ipc、mnt、uts 
- Control groups - 进行资源的限制 
- Union file systems - container与image的分层 
2.4 Docker Image
什么是Image

从基本的看起,一个典型的 Linux 文件系统由 bootfs 和 rootfs 两部分组成,bootfs(boot file system) 主要包含bootloader 和 kernel,bootloader 主要用于引导加载 kernel,当 kernel 被加载到内存中后 bootfs 会被 umount 掉。rootfs (root file system) 包含的就是典型 Linux 系统中的/dev,/proc,/bin,/etc 等标准目录和文件。
 
传统的 Linux 加载 bootfs 时会先将 rootfs 设为 read-only,然后在系统自检之后将 rootfs 从 read-only 改为 read-write,然后我们就可以在 rootfs 上进行读写操作了。但 Docker 在 bootfs 自检完毕之后并不会把 rootfs 的 read-only 改为 read-write,而是利用 union mount(UnionFS 的一种挂载机制)将 image 中的其他的 layer 加载到之前的 read-only 的 rootfs层之上,每一层 layer 都是 rootfs 的结构,并且是read-only 的。
 
查看本地的image
| 1 | docker image ls | 

image获取
- Dockerfile构建 - 创建名称为Dockerfile的文件 - 1 - touch Dockerfile - 添加如下内容 - 1 
 2
 3
 4
 5- FROM centos:centos7.6.1810 
 LABEL matintainer='maxpw'
 RUN yum install -y epel-release && yum install -y redis
 EXPOSE 6379
 ENTRYPOINT ["/usr/bin/redis-server"]- 构建image - 1 - docker bulid -t maxpw/centos-redis:latest . - 启动image实例 - 1 - docker run maxpw/centos-redis 
- Pull from Registry - 1 - docker pull centos:centos7.6.1810 
2.5 Docker Container
Docker中的Image与Container就属于面向对象中的类与对象
Image就是根据业务需求定义的一个类,而Container就是基于Image创建的一个对象实例
启动container
| 1 | docker run maxpw/centos-redis | 
交互式运行container
| 1 | docker run -it maxpw/centos-redis | 
查看启动中container列表
| 1 | docker container ls | 
查看所有的container列表
| 1 | docker container ls -a | 
删除容器
| 1 | docker container rm containerId | 
批量删除容器
| 1 | docker rm $(docker container ls -aq) | 
删除已退出的容器
| 1 | docker rm $(docker container ls -f "status=exited" -q) | 
3.Docker自定义镜像
3.1 Docker commit构建
交互式运行container
| 1 | docker run -it centos | 
安装vim
| 1 | yum install -y vim | 
完成后退出
| 1 | exit | 
将container构建为image
| 1 | ocker commit containerId maxpw/centos-vim | 
3.2 Dockerfile构建
创建目录
| 1 | mkdir centos-vim | 
创建Dockerfile文件
| 1 | touch Dockerfile | 
Dockerfile
| 1 | FROM centos | 
构建指令
| 1 | docker build -t maxpw/centos-vim-new:latest . | 
3.3 Dockerfile语法
FROM
FROM指令通常是Dockerfile文件开头的指令,选择构建自定义image的base image
| 1 | FROM scratch # no base image | 
尽量使用官方的image作为base image
LABEL
为image添加元数据信息
指令格式
| 1 | LABEL <key>=<value> <key>=<value> <key>=<value> ... | 
example
| 1 | LABEL "com.example.vendor"="ACME Incorporated" | 
RUN
run指令将在当前image上执行命名,并提交结果作为Dockerfile的下一步
两种语法格式
- RUN shell方式,命令将运行在shell上,默认使用/bin/sh -c 
- RUN [“executable”, “param1”, “param2”] exec方式
shell方式
| 1 | RUN yum update && yum install -y vim \ # 反斜线换行 | 
为了避免无用分层,请使用反斜线换行,合并多条命令
exec方式
| 1 | RUN ["yum", "install", "-y", "vim"] | 
WORKDIR
语法格式
| 1 | WORKDIR /path/to/workdir | 
workdir指令为任何run、cmd、entrypoint、copy和add指令设置工作目录
| 1 | WORKDIR /test # 如果目录不存在,则自动创建 | 
用WORKDIR,不用用RUN cd,尽量使用绝对路径目录
ADD
add指令从
两种语法格式
- ADD [–chown=: ] … 
- ADD [–chown=: ] [“ “,… “ “] 
| 1 | ADD hom* /mydir/ # adds all files starting with "hom" | 
如果URL文件使用身份验证进行保护,则需要使用run wget、run curl或使用容器中的其他工具,因为add指令不支持身份验证
如果
COPY
copy指令从
两种语法格式
- COPY [–chown=: ] … 
- COPY [–chown=: ] [“ “,… “ “] 
| 1 | COPY hom* /mydir/ # adds all files starting with "hom" | 
ENV
env指令将环境变量
两种语法格式
- ENV 
- ENV = … 
| 1 | ENV myName="John Doe" | 
尽量使用ENV增加可维护性
CMD
cmd给出的是一个容器的默认的可执行体。也就是容器启动以后,默认的执行的命令。
意味着,如果docker run没有指定任何的执行命令或者dockerfile里面也没有entrypoint,那么,就会使用cmd指定的默认的执行命令执行。
三种语法格式
- CMD ["executable","param1","param2"](exec方式)
- CMD ["param1","param2"](ENTRYPOINT默认参数)
- CMD command param1 param2(shell方式)
| 1 | FROM centos | 
一个dockerfile至多只能有一个cmd,如果有多个,只有最后一个生效一个dockerfile至多只能有一个cmd,如果有多个,只有最后一个生效
ENTRYPOINT
entrypoint用于定义容器启动以后的执行指令
两种语法格式
- ENTRYPOINT ["executable", "param1", "param2"](exec方式)
- ENTRYPOINT command param1 param2(shell方式)
| 1 | FROM ubuntu | 
4.Container操作
4.1 容器常用操作
以后台进程的方式启动容器
| 1 | docker run -it centos | 
进入运行中的容器
| 1 | docker exec -it containerId /bin/bash | 
启动停止的容器
| 1 | docker start containerId | 
停止启动的容器
| 1 | docker stop containerId | 
查看容器详细信息
| 1 | docker inspect containerId | 
4.2 容器资源限制
内存限制
| 1 | docker run -it --name=test1 --memory=200M maxpw/centos-vim | 
CPU限制
| 1 | docker run -it --name=test2 --cpu-shares=10 --memory=200M maxpw/centos-vim | 
5.Docker网络
5.1 linux命名空间
Linux的命名空间机制提供了一种资源隔离的解决方案。PID,IPC,Network等系统资源不再是全局性的,而是属于特定的Namespace。Linux Namespace机制为实现基于容器的虚拟化技术提供了很好的基础,LXC(Linux containers)就是利用这一特性实现了资源的隔离。不同Container内的进程属于不同的Namespace,彼此透明,互不干扰
Namespace是对全局系统资源的一种封装隔离,使得处于不同namespace的进程拥有独立的全局系统资源,改变一个namespace中的系统资源只会影响当前namespace里的进程,对其他namespace中的进程没有影响
Linux namespace 实现了 6 项资源隔离
| namespace | 系统调用参数 | 隔离内容 | 
|---|---|---|
| UTS | CLONE_NEWUTS | 主机和域名 | 
| IPC | CLONE_NEWIPC | 信号量、消息队列和共享内存 | 
| PID | CLONE_NEWPID | 进程编号 | 
| Network | CLONE_NEWNET | 网络设备、网络栈、端口等 | 
| Mount | CLONE_NEWNS | 挂载点 | 
| User | CLONE_NEWUSER | 用于和用户组 | 
5.2 ip netns
netns是在linux中提供网络虚拟化的一个项目,使用netns网络空间虚拟化可以在本地虚拟化出多个网络环境,目前netns在lxc容器中被用来为容器提供网络
查看已存在虚拟网络空间
| 1 | ip netns list | 
创建虚拟网络空间
| 1 | ip netns add NAME | 
进入虚拟网络空间
| 1 | ip [-all] netns exec [NAME] cmd | 
例如,进入test1网络空间
| 1 | ip netns exec test1 bash | 
查看test网络配置信息
| 1 | ip a | 
输出结果
| 1 | 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN | 
lo其实是一个系统虚拟的环回接口,它的IP地址是127.0.0.1,利用这个接口可以实现系统内部发送和接收数据,所以一般情况下我们使用下面指令:ping 127.0.0.1
查看链路层状态
| 1 | ip link | 
查看网络空间链路状态
| 1 | ip netns exec test1 ip link | 
5.3 veth pair
veth pair不是一个设备,而是一对设备,以连接两个虚拟以太网端口。操作veth pair,需要跟namespace一起配合,不然就没有意义
 
创建veth pair
| 1 | ip link add veth-test1 type veth peer name veth-test2 | 
绑定veth到网络空间
| 1 | ip link set veth-test1 netns test1 | 
绑定IP到veth
| 1 | ip netns exec test1 ip addr add 192.168.1.1/24 dev veth-test1 | 
启动veth
| 1 | ip netns exec test1 ip link set dev veth-test1 up | 
ping测试
| 1 | ip netns exec test1 ping 192.168.1.2 | 
5.4 docker bridge
我们会发现,默认创建的两个docker容器可以直接相互ping通,并且可以ping通外网,例如:ping www.baidu.com
查看当前主机docker的网络配置列表
| 1 | docker network ls | 
查看容器使用的网络模式
| 1 | docker network inspect networkId | 
查看如下信息
| 1 | "Containers": { | 
查看安装docker主机的网卡信息
| 1 | ip a | 
查看如下信息
| 1 | 5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP | 
实际上,docker0是docker在安装时做配置的一个虚拟网络,用于与多个veth进行连接,每创建一个container,都在docker所在的主机创建一个veth,与其container的虚拟网络设备进行配对
 
安装网桥查看工具
| 1 | yum install -y bridge-utils | 
查看网桥相关信息
| 1 | brctl show | 
查看如下信息
| 1 | bridge name bridge id STP enabled interfaces | 
5.5 docker link
在docker容器启动时,可以指定要链接的容器名称,就可以直接通过类似主机名的方式访问到另一台container
| 1 | docker run -it --name test3 --link test1 centos | 
5.6 docker端口映射
| 1 | docker run --name web -p 8888:80 nginx | 
6.Docker持久化
6.1 Data Volume
拉取mysql image
| 1 | docker pull mysql:5.7 | 
查看mysql Dockerfile
| 1 | VOLUME /var/lib/mysql | 
启动mysql容器
| 1 | docker run -d --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql | 
查看data volume
| 1 | docker volume ls | 
查看data volume详细信息
| 1 | docker volume inspect volumeName | 
volume name重命名
| 1 | docker run -d -v mysql:/var/lib/mysql --name mysql1 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql | 
使用已存在的data volume
| 1 | docker run -d -v mysql:/var/lib/mysql --name mysql2 -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql | 
6.2 Bind Mouting
Bind Mouting与Data Volume不同的是,Data Volume需要在Dockerfile中指定volume参数,而Bind Mouting可以直接指定本地目录与容器目录的对应关系
| 1 | docker run -it -d -v $(pwd):/opt/share --name centos-share centos |