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
2sudo 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 docker1
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
5FROM 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 |