原理与安装

原理

容器技术的核心有以下几个内核技术组成:

  • Cgroups (Control Groups) -资源管理
  • SELinux 安全
  • NameSpeace - 命名空间

Linux的NameSpace:

UTS主机名、NETWORK网络、MOUNT文件系统、USER用户、PID进程、IPC进程信号

Docker是什么

  • Docker是一款软件
  • Docker是完整的一套容器管理系统
  • Docker可以让用户非常方便的使用容器技术,而不需要过多关心底层内核的实现

Docker的优缺点

  • 优点

    相比于传统虚拟化技术,容器更加简洁高效

    传统虚拟机需要给每个VM安装造作系统

    容器使用的共享公共库和程序

  • 缺点

    容器的隔离性没有虚拟化强

    共用Linux内核,安全性有先天缺陷

安装环境

  • 需要64位操作系统
  • 至少RHEL6.5以上的版本,强烈推荐RHEL7
  • 关闭防火墙(不是必须)
  • 2G 2CPU 20G

Yum仓库配置

  • 系统包位于光盘CentOS7-1804.iso中

  • Docker软件包位于云盘kubernetes/docker中

  • Docker依赖软件包位于云盘kubernetes/extras中

1
2
3
4
5
6
7
8
9
yum install httpd createrepo

systemctl enable httpd

mkdir -p /var/www/html/localrepo

cp -a kubernetes/{docker,extras} /var/www/html/localrepo

createrepo . # 创建yum仓库

给客户机配置yum源

1
2
3
baseurl=file:///var/centos-1804

baseurl=http://192.168.1.100/localrepo

关闭防火墙和SELinux

1
2
3
systemctl disable --now firewalld

setenforce 0

安装docker

  • 开启路由转发
1
2
3
4
5
vim /etc/sysctl.conf

net.ipv4.ip_forward = 1

sysctl -p
  • 安装软件包
1
2
3
yum install -y docker-ce

systemctl enable --now docker

镜像管理

什么是镜像?

  • 镜像是启动容器的核心
  • 在docker中容器是基于镜像启动的
  • 镜像采用分层设计
  • 使用COW技术

镜像来源

镜像可以从官方仓库下载,也可以自己制作

官方镜像仓库:

查看本机镜像:

  • docker images

获取镜像

  • 查找镜像

    docker search 关键字

    docker search busybox

  • 下载镜像

    docker pull 镜像名称:标签

    docker pull docker.io/busybox

镜像的备份与恢复

  • 备份镜像(导出镜像)

    docker save 镜像名称:镜像标签 -o 备份文件名 (tar格式)

    docker save docker.io/busybox:latest -o busybox.tar

  • 恢复镜像(导入镜像)

    docker load -i 备份文件名称

    docker load -i busybox.tar

镜像的名称和标签

  • 指定镜像的方法
  • 每一个镜像都对应唯一的镜像id
  • 镜像名称(文件名称)+标签(路径)==唯一
  • 每一个镜像都有标签,如果没写就是默认标签latest
  • 我们在调用镜像的时候,如果没有指定默认也是latest

导入已有镜像,镜像的备份包位于kubernetes/docker-images下

  • centos
  • nginx
  • redis
  • Ubuntu

docker容器管理

运行容器

  • docker run 命令

    docker run -参数 镜像名称:镜像标签 启动命令

  • 查看run的参数

    docker help run

    man docker-run

    run = 创建+启动+进入

启动centos容器,并进入容器

  • 参数-i,交互式
  • 参数-t,终端
  • 参数-d,后台运行
  • 参数–name,容器名字

docker run -it centos:latest /bin/bash

镜像管理命令

查看镜像

  • docker images

查找镜像(在官方仓库查找)

  • docker search

删除镜像

  • docker rmi 镜像名称:镜像标签

上传下载镜像

  • docker pull 镜像名称:镜像标签

  • docker push 要上传的镜像名称:镜像标签

备份恢复镜像

  • docker save 镜像名称:镜像标签 -o 备份文件名称
  • docker load -i 备份文件名称

查看镜像的制作历史

  • docker history 镜像名称:镜像标签

查看镜像的信息

  • docker inspect 镜像名称:镜像标签

镜像的新名称和标签

  • docker tag 镜像名称:镜像标签 新镜像名称:新的标签

容器管理命令

启动容器

  • docker run -参数 镜像名称:镜像标签 启动命令

查看容器

  • docker ps [-a 所有容] [-q 只显示容器id]

删除容器

  • docker rm 容器id

  • docker rm -f $(docker ps -aq)

将容器保存为镜像

  • docker commit -a “作者” -m “文字说明” 容器id 镜像名:标签

容器管理命令启动、停止、重启

  • docker start|stop|restart 容器id

查看容器内进程

  • docker top 容器id

拷贝文件

  • docker cp 本机文件路径 容器id:容器内路径(上传)
  • docker cp 容器id:容器内路径 本机文件路径(下载)

查看容器信息

  • docker inspect 容器id

连接容器启动进程

  • docker attach 容器id
  • exit 退出后容器关闭
  • 有些进程无法与用户交互 不能管理容器

连接容器,启动新进程

  • docker exec -it 容器id 启动命令(/bin/bash)

容器与应用

前台服务/后台服务

容器的启动进程后台运行 ≠ 容器在后台运行

容器的服务

  • 前台服务(-it)

    一般能与用户交互的程序,比如/bin/bash,/bin/sh等

  • 后台服务(-itd)

    一般是一个程序,比如apache、nginx、redis等

容器服务安装

在centos容器中安装apache

  • 启动一个容器

    docker run -it –name myapache centos:latest

  • 配置yum仓库(与宿主机使用相同的仓库)

    –删除容器内默认的仓库配置(容器内执行)

    rm -f /etc/yum.repos.d/*.repo

    –把宿主机上的仓库配置文件拷贝到容器内(在宿主机上执行)

    docker cp local.repo myapache:/etc/yum.repo.d/

  • 安装apache (容器内执行)

    yum install -y httpd php

  • 查看启动文件及变量(容器内执行)

    –文件路径/usr/lib/systemd/httpd.service

    –启动命令可以查看service文件中的ExecStart

    –环境变量查询服务文件中EnvironmenrFile指定的文件内容

    cat /usr/lib/systemd/system/httpd.service

    cat /etc/sysconfig/httpd

  • 启动服务(容器内执行)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 设置默认首页

cd /var/www/html

echo 'hello word' > index.html

# 启动服务

export LANG=C # 设置变量

/usr/sbin/httpd -DFOREGROUND

# -DFOREGROUND 表示启动进程在前台运行

# 不加 退出容器 进程就会关闭 (ctrl+p+q退出后容器不关闭)
  • 验证服务

    curl http://容器IP/ #访问

自定义镜像

COW技术原理

  • Copy On Write 写时复制技术
  • 直接映射原始盘的数据内容
  • 当数据有写入需求时,写入之前自动将数据块拷贝存入前端盘中后,对前端盘进行修改
  • 原始盘始终是只读的

自定义镜像原理

  • 镜像采用分层设计
  • 创建读写层
  • 修改配置
  • 重新打包

基础镜像

  • 容器(运行各种应用)
  • 应用层镜像(多个)
  • 基础镜像 (在此制作)
  • 原始镜像(官方下载版)

制作基础镜像

commit命令

使用commit制作基础镜像

  • 启动原始镜像,配置yum源,并安装软件包
  • 使用commit制作新的镜像
1
2
3
4
5
6
7
8
9
docker run -it centos:lastest

# 配置yum源,安装长用软件

exit

docker commit 容器id myos:latest(新镜像名:标签)

docker images #查看

commit的局限

  • 很容易制作简单的镜像,但碰到复杂的境况就十分不方便,例如碰到以下情况:
  • 需要设置默认的启动命令
  • 需要设置环境变量
  • 需要指定镜像开放某些特定的端口
  • Dockerfile是一种更强大的镜像制作方式
  • 编写类似脚本的Dockerfile文件,通过该文件制作镜像

Dockerfile语法

  • FROM:基础镜像
  • MAINTAINER:镜像维护者姓名
  • RUN:制作镜像时执行的命令
  • ADD:复制文件到镜像,自动解压
  • COPY:复制文件到镜像,不解压
  • EXPOSE:声明开放的端口
  • ENV:声明容器启动后的环境变量
  • WORKDIR:定义容器默认工作目录(等于cd)
  • CMD:容器启动时执行的命令,仅可以有一条CMD
  • ENTERYPOINT : 类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖
  • VOLUME : 定义匿名数据卷
  • ONBUILD : 用于延迟构建命令的执行就是用此镜像构建新的镜像时执行的命令
  • LABEL : 用来给镜像添加一些元数据(metadata),以键值对的形式
  • HEALTHCHECK : 用于指定某个程序或者指令来监控 docker 容器服务的运行状态。
  • ARG : 构建参数,与 ENV 作用一至。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效

docker build 命令

  • docker build 根据Dockerfile里的内容生成镜像
  • 使用Dockerfile工作流程
  • 编写Dockerfile
  • 生成镜像
  • docker build -t 镜像名称:标签 Dockerfile所在目录

服务镜像案例

  • 创建apache + php 服务镜像
  • 核心配置CMD [“/usr/bin/httpd”,”-DFOREGROUND”]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
vim Dockerfile

FROM myos:latest #指定父镜像

RUN yum install -y httpd php #安装apache服务

ENV LANG=C #设置环境变量

ADD webhome.tar.gz /var/www/html #安装网页文件

WORKDIR /var/www/html/ #指定工作目录(cd)

EXPOSE 80 #声明开放端口

CMD ["/usr/bin/httpd","-DFOREGROUND"] #容器启动命令
  • 验证镜像服务
1
2
3
4
5
6
7
8
9
# 创建镜像,并验证

docker build -t myos:httpd .

docker run -itd myos:httpd #后台服务参数d

docker inspect 容器id #查看IP地址

curl -i http://ip/

docker与微服务

微服务是什么

  • 微服务是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值
  • 微服务架构有别于更为传统的单体式方案,将应用拆分为多个核心功能,可以单独架构和部署
  • 微服务架构不只是应用核心功能间的这种松散耦合,它还涉及如何进行服务间通信以应对不可避免的故障、满足未来的可拓展性并实现新的功能集成

微服务优点

  • 它解决了复杂性的问题。它将单体应用分解为一组服务。虽然功能总量不变,但应用程序已被分解为可管理的模块或服务,这种体系结构使得每个服务都可以独立开发、运行,降低了服务的耦合性更适合CI/CD

  • 微服务的优点是

    高度可拓展性、出色的弹性、易于部署、易于访问、更加易于开发

    松耦合高内聚

如何构建微服务

  • 微服务的核心就是“拆”
  • 如何拆分服务?
  • 要想构建微服务就要理清各个服务之间的关系
  • 保持服务的持续演进,使服务能够快速、低成本地拆分和合并,以快速响应业务的变化,持续迭代
  • docker这种应用的管理模式正是微服务的思想,每个容器承载一个服务。一台计算机同时运行多个容器,从而就能很轻松地模拟出复杂的微服务架构

高级服务镜像概述

  • 制作一个Nginx + php-fpm 服务

  • 容器服务拆分

  • 拆分Nginx与php-fpm服务

  • nginx镜像

    nginx只负责前端静态页面

  • php-fpm镜像

    php-fpm通过内部网络为nginx提供解析服务

创建php-fpm镜像

  • www.conf 配置文件(/etc/php-fpm.d/)
  • listen = 0.0.0.0:9090 # 修改
  • listen.allwoed_cllents=127.0.0.1 #删除

Dockerfile

1
2
3
4
5
6
7
8
9
10
11
12
13
FROM myos:latest

RUN yum install -y php-fpm

COPY www.conf /etc/php-fpm.d/www.conf

EXPOSE 9090

WORKDIR /usr/local/nginx/html

COPY info.php info.php

CMD ["/usr/sbin/php-fpm", "--nodaemonize"]
  • 查询系统服务

    cat /usr/lib/systemd/systemd/php-fpm

  • 环境变量文件

    EnvironmentFile=/etc/sysconfig/php-fpm

  • 查询是否有需要定义变量参数

    /etc/sysconfig/php-fpm

  • 启动命令

    ExecStart=/usr/sbin/php-fpm –nodaemonize

nginx镜像

  • nginx镜像创建技巧
  • nginx一般采用编译安装,在容器内编译不容易排错也不便于管
  • Dockerfile中ADD可以将一个压缩包在容器内解压释放
  • 利用这一特性,我们可以在外部编译nginx,并把编译好的文件打包,使用打包文件构建nginx镜像服务
  • nginx进程默认在后台进行,我们必须强制在前台运行
  • 使用参数daemon off;

nginx安装包

  • 编译nginx并打包
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
yum install -y gcc make pcre-devel openssl-devel  #依赖包

useradd nginx

tar -zxvf nginx-1.12.2.tar.gz

cd nginx-1.12.2

./configure \
> --prefix=/usr/local/nginx \ #安装路径
> --user=nginx --group=nginx \ #默认用户组
> --with-http_ssl_module #加密模块

make && make install

cd /usr/local/nginx/html

cp info.html info.php /usr/local/nginx/html #测试页面

cd /usr/local/

tar czf nginx.tar.gz nginx #程序目录打包

nginx镜像创建

  • Dockerfile
1
2
3
4
5
6
7
8
9
10
11
FROM myos:latest

RUN yun install -y pcrp openssl && yum clean all && useradd nginx

ADD nginx.tar.gz /usr/local/

EXPOSE 80

WORKDIR /usr/local/nginx/html

CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"]
  • 创建镜像

    docker build -t myos:nginx .

容器服务管理

对外发布容器服务

怎么访问docker服务

  • 默认容器可以访问外网
  • 但外部网络的主机不可以访问容器内的资源
  • 容器每次创建IP地址都会改变
  • 解决这个问题的最佳方法是端口绑定
  • 容器可以与宿主机的端口进行端口绑定
  • 从而把宿主机变成对应的服务,不用关心容器的IP地址

发布docker任务

  • 我们使用-p参数把容器端口和宿主机端口绑定

  • 同一宿主机端口只能绑定一个容器服务

  • -p [可选ip]:宿主机端口:容器端口 (可有多个)

  • 例如:把宿主机变成apache

    docker run -itd -p 80:80 myos:httpd

  • 例如:把宿主机变成nginx

    docker run -itd -p 80:80 myos:nginx

容器共享卷

nginx解析PHP

  • nginx不能解析PHP怎么办?

    修改nginx配置文件,把PHP交给后端服务解析

    php-fpm容器作为后端解析php程序

  • 如何修改nginx配置文件

    进入容器修改

卷的用途

  • Docker容器不适合保存任何数据
  • 数据文件与配置文件频发更改
  • 修改多个容器内的数据非常困难
  • 多容器之间有数据共享、同步需求
  • 重要数据在容器内不方便管理易丢失
  • 解决这些问题请使用主机卷映射功能

主机卷的映射

docker可以映射宿主机文件或目录到容器中

  • 目标对象不存在就自动创建
  • 目标文件存在就直接覆盖掉
  • 多容器可以映射同一目标对象来达到数据共享目的

启动容器时,使用-v映射参数(可以有多个)

  • docker run -itd -v 宿主机对象:容器内对象 镜像名称:标签
  • docker run -itd -v 宿主机:容器:ro centos(容器内只读)

卷映射案例

在宿主机上修改nginx配置文件,把配置文件通过卷映射到容器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 启动PHP后端容器

docker run -itd --name myphp myos:php-fpm

# 查看后端容器IP

docker inspect myphp

# 创建存放配置文件的目录

mkdir /var/webconf

cp /usr/local/nginx/conf/nginx.conf /var/webconf/

vim /var/webconf/nginx.conf

​ location ~…… #取消注释

​ fastcgi_pass 172.12.0.XX:9000;
# 先运行myos:php-fpm
# docker inspect 容器id 查看ip

# 删除fastcgi_param……一行

​ include fastcgi.conf # params改为conf

docker run -itd -p 80:80 -v /var/webconf/nginx.conf:/usr/local/nginx/config/nginx.conf myos:nginx

docker 的数据卷容器

  • 使用 dockerfile 构建包含数据卷的镜像
1
2
3
4
5
6
7
8
vim dockerfile
FROM centos
VOLUME ["/datavolume3","/datavolume6"]
CMD /bin/bash

docker build -t volumez:latest .
docker run --name volume-dubble -it volume
会看到这个容器下有两个目录,/datavolume3 和/datavolume6

挂载数据卷容器的方法

  • docker run –volumes-from [container name]
1
2
3
4
5
6
7
8
# volume这个镜像是上面创建的带两个数据卷/datavolume和/ddatavolume6的镜像
docker run --name data-volume -itd volume

docker exec -it data-volume /bin/bash(进入到容器中)

touch /datavolume6/lucky.txt

exit
  • 创建一个新容器挂载刚才 data-volume 这个容器创建的数据卷
1
2
3
4
5
6
7
8
9
docker run --name data-volume2 --volumes-from data-volume -itd centos /bin/bash

docker exec -it data-volume2 /bin/bash

# 查看容器的/datavolume6 目录下是否新创建了 lucky.txt 文件

cd /datavolume6

ls

docker 数据卷的备份和还原

  • 数据备份方法
  • docker run –volumes-from [container name] -v $(pwd):/backup centos tar czvf /backup/backup.tar [container data volume]
1
2
3
4
5
6
docker run --volumes-from data-volume2 -v /root/backup:/backup --name datavolume-copy centos tar zcvf /backup/data-volume2.tar.gz /datavolume6

# 基于centos镜像,启动一个名为datavolume-copy2的容器
# 把宿主机/root/bachup挂载到容器/backup
# 并把data-volume2中的挂载卷挂载到容器datavolume-copy2
# 执行压缩命令tar zcvf /backup/data-volume2.tar.gz /datavolume6
  • 数据还原方法
  • docker run –volumes-from [container name] -v $(pwd):/backup centos tar xzvf /backup/backup.tar.gz [container data volume]
1
2
3
4
5
6
7
8
9
10
11
12
13
# 删除lucky.txt文件
docker exec -it data-volume2 /bin/bash

cd /datavolume6

rm -rf lucky.txt

# 创建容器,解压之前的备份
docker run --volumes-from data-volume2 -v /root/backup/:/backup centos tar zxvf /backup/data-volume2.tar.gz -C /datavolume6

# 可以看到还原后的数据
docker exec -it data-volum2 /bin/bash
cd /datavolum6

容器网络通信

nginx如何调用后端php-fpm

  • php-fpm监听网络端口,从网络把服务传递进来

php-fpm与nginx如何共享网页文件

  • 后端解析传递的文件是文件路径,可以使用宿主机的共享卷

  • 在nginx和php-fpm中共享目录

php-fpm经常变化怎么办

docker 容器的网络基础

安装 docker 的时候,会生成一个 docker0 的虚拟网桥

Linux 虚拟网桥的特点,可以设置 ip 地址,相当于拥有一个隐藏的虚拟网卡

1
2
3
4
5
ip addr
docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:f0:9b:8c:e6 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever

每运行一个 docker 容器都会生成一个 veth 设备对,这个 veth 一个接口在容器里,一个接口在物理机上。

  • 安装网桥管理工具
1
2
3
4
5
6
7
8
9
# brctl show可以查看到有一个docker0的网桥设备,下面有很多接口,每个接口都表示一个启动的docker容器
yum install bridge-utils -y

brctl show

bridge name bridge id STP enabled interfaces
docker0 8000.0242f09b8ce6 no vethdb5abf4
vethdd051b9
vethe0ff34c

docker 容器的互联

  • 下面用到的镜像的 dockerfile 文件
1
2
3
4
5
6
7
8
9
FROM centos
RUN rm -rf /etc/yum.repos.d/*
COPY CentOS-Base.repo /etc/yum.repos.d/
RUN yum install wget -y
RUN yum install nginx -y
EXPOSE 80
CMD /bin/bash

docker build -t inter-image .

允许所有容器间互联

  • 第一种方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 基于inter-image镜像启动第一个容器test1
docker run --name test1 -itd inter-image

# 进入到容器里面启动 nginx
/usr/sbin/ngnx

# 基于上面的 inter-image 镜像启动第二个容器 test2
docker run --name test2 -itd inter-image

# 进入到 test1 容器和 test2 容器,可以看两个容器的 ip,分别是 172.17.0.20 和 172.17.0.21

# 可以看见能 ping 同 test1 容器的 ip
docker exec -it test2 /bin/bash ping 172.17.0.20

# 可以访问到test1容器的内容
curl http://172.17.0.20

上述方法假如 test1 容器重启,那么在启动就会重新分配 ip 地址,所以为了使 ip 地址变了也可以访问,可以采用给目标主机设置别名的方法

docker link 设置网络别名

  • 第二种方法

可以给容器起一个代号,这样可以直接以代号访问,避免了容器重启 ip 变化带来的问题

  • docker run –link=[CONTAINER_NAME]:[ALIAS] [IMAGE] [COMMAND]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 启动一个 test3 容器
docker run --name test3 -itd inter-image /bin/bash

# 启动一个test5容器,--link做链接,那么当我们重新启动test3容器时,就算ip变了,也没关系,我们可以在 test5 上 ping 别名 webtest

docker run --name test5 -itd --link=test3:webtest inter-image /bin/bash

# test3和test5的ip分别是172.17.0.22和172.17.0.24

# 重启test3容器 发现ip变成了172.17.0.25
docker restart test3

# 进入到test5容器
docker exec -it test5 /bin/bash

# ping test3容器的ip别名webtest可以ping通,尽管test3容器的ip变了也可以通

docker的网络通信模式

  • host模式,与宿主机共享网络,使用–net =host 指定
  • container模式,共享其他容器的网络命名空间,使用–net =container:NAME orID 指定
  • none模式,无网络模式,使用–net =container:NAME orID 指定
  • bridge模式,默认模式
  • 自定义网络,自由创建桥接网络或者overlay网络

none 模式

Docker 网络 none 模式是指创建的容器没有网络地址,只有 lo 网卡

1
2
3
4
5
6
7
8
9
10
docker run -itd --name none --net=none --privileged=true centos 

docker exec -it none /bin/bash

# 只有本地 lo 地址
[root@05dbf3f2daaf /]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever

container 模式

Docker 网络 container 模式是指,创建新容器的时候,通过–net container 参数,指定其和已经存在的某个容器共享一个 Network Namespace。

因此新建的容器就不会拥有自己独立的 IP,而是共享左边容器的 IP ,端口范围等网络资源,两个容器的进程通过 lo 网卡设备通信。

  • 和已经存在的 none 容器共享网络
1
2
3
4
5
6
7
docker run --name container2 --net=container:none -it --privileged=true centos

[root@05dbf3f2daaf /]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever

bridge 模式

默认选择 bridge 的情况下,容器启动后会通过 DHCP 获取一个地址

  • 创建桥接网络
1
2
3
4
5
6
7
8
9
10
11
12
docker run --name bridge -it --privileged=true centos bash

ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever

64: eth0@if65: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:ac:11:00:0d brd ff:ff:ff:ff:ff:ff link-netnsid 0
inet 172.17.0.13/16 brd 172.17.255.255 scope global eth0
valid_lft forever preferred_lft forever

host 模式

Docker 网络 host 模式是指共享宿主机的网络

  • 共享宿主机网络
1
2
3
docker run --name host -it --net=host --privileged=true centos

ip addr

容器网络共享

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
mkdir /var/webroot  # 创建共享网页目录

cp info.php info.html index.html /var/webroot/

vim nginx.conf # 修改配置文件,增加PHP支持

…………

​ fastcgi_pass 127.0.0.1:9000;

…………

# 创建nginx容器

docker run -itd --name nginx -p 80:80 \
-v /var/webconf/nginx.conf:/usr/local/nginx/conf/nginx.conf\
-v /var/webroot:/usr/local/nginx/html myos:nginx


# 创建PHP容器 共享nginx网络

docker run -itd --network=container:nginx \
-v /var/webroot:/usr/local/nginx/html myos:php-fpm

docker 资源配额

docker 容器控制 cpu

Docker 通过 cgroup 来控制容器使用的资源限制,可以对 docker 限制的资源包括 CPU、内存、磁盘

  • 查看配置份额的帮助命令:

  • docker run –help | grep cpu-shares

  • -c, –cpu-shares int CPU shares (relative weight)

CPU shares (relative weight) 在创建容器时指定容器所使用的 CPU 份额值。cpu-shares 的值不能保证可以获得 1 个 vcpu 或者多少 GHz 的 CPU 资源,仅仅只是一个弹性的加权值。

默认每个 docker 容器的 cpu 份额值都是 1024。在同一个 CPU 核心上,同时运行多个容器时,容器的cpu 加权的效果才能体现出来。

两个容器 A、B 的 cpu 份额分别为 1000 和 500,结果会怎么样

  • 情况 1:A 和 B 正常运行,占用同一个 CPU,在 cpu 进行时间片分配的时候,容器 A 比容器 B 多一倍的机会获得 CPU 的时间片。

  • 情况 2:分配的结果取决于当时其他容器的运行状态。比如容器 A 的进程一直是空闲的,那么容器 B是可以获取比容器 A 更多的 CPU 时间片的; 比如主机上只运行了一个容器,即使它的 cpu 份额只有50,它也可以独占整个主机的 cpu 资源。

cgroups 只在多个容器同时争抢同一个 cpu 资源时,cpu 配额才会生效。因此,无法单纯根据某个容器的 cpu 份额来确定有多少 cpu 资源分配给它,资源分配结果取决于同时运行的其他容器的 cpu 分配和容器中进程运行情况。

1
2
3
4
5
6
7
# 给容器实例分配 512 权重的 cpu 使用份额
# 参数: --cpu-shares 512
docker run -it --cpu-shares 512 centos /bin/bash

cat /sys/fs/cgroup/cpu/cpu.shares # 查看结果:

512

CPU core 核心控制

  • 参数:–cpuset 可以绑定 CPU

对多核 CPU 的服务器,docker 还可以控制容器运行限定使用哪些 cpu 内核和内存节点,即使用–cpuset-cpus 和–cpuset-mems 参数。对具有 NUMA 拓扑(具有多 CPU、多内存节点)的服务器尤其有用,可以对需要高性能计算的容器进行性能最优的配置。如果服务器只有一个内存节点,则–cpuset-mems 的配置基本上不会有明显效果。

  • CPU 配额控制参数的混合使用

在上面这些参数中,cpu-shares 控制只发生在容器竞争同一个 cpu 的时间片时有效。 如果通过 cpuset-cpus 指定容器 A 使用 cpu 0,容器 B 只是用 cpu1,在主机上只有这两个容器使用对应内核的情况,它们各自占用全部的内核资源,cpu-shares 没有明显效果。

容器 A 和容器 B 配置上 cpuset-cpus 值并都绑定到同一个 cpu 上,然后同时抢占 cpu 资源,就可以看出效果了。

测试 cpu-shares 和 cpuset-cpus 混合使用运行效果,就需要一个压缩力测试工具stress 来让容器实例把 cpu 跑满。

  • stress 命令
  • linux 系统压力测试软件 Stress 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
yum install -y epel-release 

yum install stress -y

# stress 参数解释
-? 显示帮助信息

-v 显示版本号

-q 不显示运行信息

-n 显示已完成的指令情况

-t --timeout N 指定运行 N 秒后停止

--backoff N 等待 N 微妙后开始运行

-c 产生 n 个进程 :每个进程都反复不停的计算随机数的平方根,测试 cpu

-i 产生 n 个进程 :每个进程反复调用 sync(),sync()用于将内存上的内容写到硬盘上,测试磁盘 io

-m --vm n 产生 n 个进程,每个进程不断调用内存分配 malloc()和内存释放 free()函数 ,测试内存

--vm-bytes B 指定 malloc 时内存的字节数 (默认 256MB)

--vm-hang N 指定在 free 栈的秒数

-d --hadd n 产生 n 个执行 write 和 unlink 函数的进程

-hadd-bytes B 指定写的字节数

--hadd-noclean 不 unlink

# 注:时间单位可以为秒 s,分 m,小时 h,天 d,年 y,文件大小单位可以为 K,M,G

# 产生 2 个 cpu 进程,2 个 io 进程,20 秒后停止运行
# 如果执行时间为分钟,改 20s 为 1m
stress -c 2 -i 2 --verbose --timeout 20s

# top 按1 查看

测试 cpuset-cpus 和 cpu-shares 混合使用运行效果,就需要一个压缩力测试工具 stress 来让容器实例把 cpu 跑满。 当跑满后,会不会去其他 cpu 上运行。 如果没有在其他 cpu 上运行,说明cgroup 资源限制成功。

创建两个容器实例:docker10 和 docker20。 让 docker10 和 docker20 只运行在 cpu0 和cpu1 上,最终测试一下 docker10 和 docker20 使用 cpu 的百分比。

1
2
3
4
5
# 指定docker10只能在cpu0和cpu1上运行,而且docker10的使用cpu的份额512
docker run -itd --name docker10 --cpuset-cpus 0,1 --cpu-shares 512 centos /bin/bash

# 指定 docker20 只能在 cpu0 和 cpu1 上运行,而且 docker20 的使用 cpu 的份额 1024,比 dcker10 多一倍
docker run -itd --name docker20 --cpuset-cpus 0,1 --cpu-shares 1024 centos /bin/bash
  • 进入 docker10,使用 stress 测试进程是不是只在 cpu0,1 上运行
1
2
3
4
5
6
7
8
9
10
docker exec -it docker10 /bin/bash

# 安装 epel 扩展源
yum install -y epel-release

# 安装 stress 命令
yum install stress -y

# 运行 2 个进程,把两个 cpu 占满
stress -c 2 -v -t 10m
  • 在物理机另外一个虚拟终端上运行 top 命令,按 1 快捷键,查看每个 cpu 使用情况,可看到正常。只在 cpu0,1 上运行
1
2
3
4
5
6
7
8
9
10
top - 11:08:13 up  1:56,  3 users,  load average: 1.33, 0.34, 0.15
Tasks: 208 total, 5 running, 203 sleeping, 0 stopped, 0 zombie
%Cpu0 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu2 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu3 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu4 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu5 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 4028428 total, 1983164 free, 836624 used, 1208640 buff/cache
KiB Swap: 1048572 total, 1048572 free, 0 used. 2848060 avail Mem
  • 然后进入 docker20,使用 stress 测试进程是不是只在 cpu0,1 上运行,且 docker20 上运行的 stress 使用 cpu 百分比是 docker10 的 2 倍
1
2
3
4
5
6
7
docker exec -it docker20 /bin/bash 

yum install -y epel-release

yum install stress -y

stress -c 2 -v -t 10m
  • 在另外一个虚拟终端上运行 top 命令,按 1 快捷键,查看每个 cpu 使用情况

注:两个容器只在 cpu0,1 上运行,说明 cpu 绑定限制成功。而 docker20 是 docker10 使用 cpu 的 2倍。说明–cpu-shares 限制资源成功。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
top - 11:10:37 up  1:59,  3 users,  load average: 3.76, 1.75, 0.70
Tasks: 207 total, 5 running, 202 sleeping, 0 stopped, 0 zombie
%Cpu0 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu1 :100.0 us, 0.0 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu2 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu3 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu4 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
%Cpu5 : 0.0 us, 0.0 sy, 0.0 ni,100.0 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
KiB Mem : 4028428 total, 1983484 free, 836304 used, 1208640 buff/cache
KiB Swap: 1048572 total, 1048572 free, 0 used. 2848380 avail Mem

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
6576 root 20 0 7960 92 0 R 100.0 0.0 2:01.97 stress
6575 root 20 0 7960 92 0 R 50.0 0.0 1:37.31 stress
6527 root 20 0 7960 96 0 R 25.3 0.0 0:59.87 stress
6528 root 20 0 7960 96 0 R 25.0 0.0 1:00.23 stress

docker 容器控制内存

  • Docker 提供参数-m, –memory=””限制容器的内存使用量
1
2
3
4
5
6
7
8
# 允许容器使用的内存上限为 128M: 
docker run -it -m 128m centos

cat /sys/fs/cgroup/memory/memory.limit_in_bytes
134217728

# 创建一个 docker,只使用 2 个 cpu 核心,只能使用 128M 内存
docker run -it --cpuset-cpus 0,1 -m 128m centos

docker 容器控制 IO

  • 防止某个 Docker 容器吃光你的磁盘 I / O 资源
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
docker run --help | grep write-bps
--device-write-bps value Limit write rate (bytes per second) to a device (default [])

# 限制此设备上的写速度(bytes per second),单位可以是 kb、mb 或者 gb。
--device-read-bps value


# 限制容器实例对硬盘的最高写入速度设定为 2MB/s。
--device 参数:将主机设备添加到容器

mkdir -p /var/www/html/

docker run -it -v /var/www/html/:/var/www/html --device /dev/sda:/dev/sda --device-write-bps /dev/sda:2mb centos /bin/bash

time dd if=/dev/sda of=/var/www/html/test.out bs=2M count=50 oflag=direct,nonblock

# 注:dd 参数:
# direct:读写数据采用直接 IO 方式,不走缓存。直接从内存写硬盘上。
# nonblock:读写数据采用非阻塞 IO 方式,优先写 dd 命令的数据

# 发现 1 秒写 2M。 限制成功。
50+0 records in
50+0 records out
52428800 bytes (52 MB) copied, 50.1831 s, 2.0 MB/s

real 0m50.201s
user 0m0.001s
sys 0m0.303s

docker 容器运行结束自动释放资源

  • 当容器命令运行结束后,自动删除容器,自动释放资源
1
2
3
4
5
6
7
8
docker run --help | grep rm 
--rm Automatically remove the container when it exits


docker run -it --rm --name xianchao centos sleep 6

# 等 5s 后,再查看,自动删除了
docker ps | grep xianchao

私有仓库

Harbor

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
mkdir /data/ssl -p

cd /data/ssl/

# 生成 ca 证书
# 生成一个 3072 位的 key,也就是私钥
openssl genrsa -out ca.key 3072

# 生成一个数字证书ca.pem,3650表示证书的有效时间是10年
openssl req -new -x509 -days 3650 -key ca.key -out ca.pem
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:henan
Locality Name (eg, city) [Default City]:nanyang
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:
Email Address []:

# 参数解析
-new:生成新证书部署请求
-x509:是个生成自签格式证书,专用于创建私有CA时
-key 生成请求时用到的私有文件路径
-out:生成的请求文件路径,如果自签操作直接生成部署证书
-days:证书的有效时长,单位是天


# 生成域名的证书
# 生成一个 3072 位的 key,也就是私钥
openssl genrsa -out harbor.key 3072

# 生成一个证书请求,一会签发证书时需要的
openssl req -new -key harbor.key -out harbor.csr
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:henan
Locality Name (eg, city) [Default City]:nanyang
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:harbor
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

# 签发证书:
openssl x509 -req -in harbor.csr -CA ca.pem -CAkey ca.key -CAcreateserial -out harbor.pem -days 3650

Signature ok # 显示ok,说明证书签发好了
subject=/C=CN/ST=henan/L=nanyang/O=Default Company Ltd/CN=harbor
Getting CA Private Key

安装Harbor

  • 初始化操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 关闭防火墙
systemctl disable --now firewalld

# 关闭selinux
[root@harbor ~]# setenforce 0
[root@harbor ~]# sed -i "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config

# 配置时间同步
chronyc sources
210 Number of sources = 1
MS Name/IP address Stratum Poll Reach LastRx Last sample
===============================================================================
^* time.cloudflare.com 3 6 77 84 +315us[-2646us] +/- 115ms

# 配置hosts解析
cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.1.10 docker
192.168.1.11 harbor

# 安装基础软件包
yum install -y wget net-tools nfs-utils lrzsz gcc gcc-c++ make cmake libxml2-devel openssl-devel curl curl-devel unzip sudo ntp libaio-devel vim ncurses-devel autoconf automake zlib-devel python-devel epel-release openssh-server socat ipvsadm conntrack
  • 安装docker-ce
1
2
3
4
5
6
7
8
9
10
11
# 配置docker-ce国内yum源
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo

# 安装docker依赖包
yum install -y yum-utils device-mapper-persistent-data lvm2

# 安装docker
yum install -y docker-ce

# 启动服务
systemctl enable --now docker
  • 修改内核参数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# br_netfilter 模块用于将桥接流量转发至 iptables 链,br_netfilter 内核参数需要开启转发。
modprobe br_netfilter

cat > /etc/sysctl.d/docker.conf <<EOF
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.ip_forward = 1
EOF

sysctl -p /etc/sysctl.d/docker.conf

scp docker:/etc/docker/daemon.json /etc/docker/daemon.json

# 重启docker
systemctl daemon-reload && systemctl restart docker
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# 创建安装目录
mkdir /data/install -p
cd /data/install/

# 安装docker-compose
mv docker-compose-Linux-x86_64.64 /usr/bin/docker-compose

chmod +x /usr/bin/docker-compose

# 解压harbor需要的镜像
docker load -i docker-harbor-2-3-0.tar.gz

# 安装 harbor
tar zxvf harbor-offline-installer-v2.3.0-rc3.tgz

cd harbor
cp harbor.yml.tmpl harbor.yml

vim harbor.yml
# 修改配置文件:
hostname: harbor
# 修改 hostname,跟上面签发的证书域名保持一致
# 协议用 https
certificate: /data/ssl/harbor.pem
private_key: /data/ssl/harbor.key

./install.sh

修改docker配置

1
2
3
4
5
6
7
8
vim /etc/docker/daemon.json
"insecure-registries": ["192.168.40.181","harbor"]

systemctl daemon-reload && systemctl restart docker

docker login 192.168.40.181
Username:admin
Password: Harbor12345

docker-distribution

安装私有仓库(服务端)

  • yum install -y docker-distribution

启动私有仓库,并设置开机自启动

  • systemctl enable –now docker-disrtibution

私有仓库的配置

  • /etc/docker-distribution/registry/config.yml

  • /var/lib/registry

  • 默认端口号5000

我们可以通过curl命令访问仓库

  • curl http://仓库ip:5000/v2/_catalog

docker配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
vim /etc/docker/daemon.json
{
# cgroup驱动,docker默认cgroupfs

"exec-opts": ["native.cgroupdriver=systemd"]

# 默认下载仓库

"registry-mirrors": ["https://hub-mirror.c.163.com"]

# 私有仓库地址(重点)

"insecure-registries":["192.168.1.100:5000", "registry:5000"]
}

重启docker服务(停止所有容器,容器太多可能会卡死)

  • docker rm -f $(docker ps -aq)

  • systenctl restart docker

上传镜像

为镜像创建标签后上传:

  • docker tag 镜像:标签 私有仓库ip:5000/镜像:标签
  • docker push 私有仓库ip:5000/镜像:标签#上传
  • docker tag myos:latest 192.168.1.100:5000/myos:latest
  • docker push 192.168.1.100:5000/myos:latest

管理仓库

查看私有仓库中的镜像名称或标签

下载镜像

  • docker pull 镜像:标签

  • 在客户端上启动docker并配置好daemon.json

  • 在内网中配置好私有仓库文件不用下载镜像可直接运行启动

  • docker run -itd 192.168.1.100:5000/myos:latest