Docker基础

目录

Docker基础

视频连接:戳我哦

1、Docker概述

Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从 Apache2.0 协议开源。

Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化。

容器是完全使用沙箱机制,更重要的是容器性能开销极低。

Docker 从 17.03 版本之后分为 CE(Community Edition: 社区版) 和 EE(Enterprise Edition: 企业版)

  • 开源容器引擎
  • 操作系统级别的虚拟化技术,进程级别的隔离
  • 依赖于linux内核特性:namespace(资源隔离)和Cgroup(资源限制)
  • 一个简单的应用打包工具

2、容器 VS 虚拟机

image-20220108131513402

image-20220108121944440

3、Docker组成

  • docker client
  • docker daemon
  • docker image
  • docker container
  • docker registry

image-20220108121759260

4、Docker安装部署

官方地址:https://docs.docker.com/engine/install/ubuntu/

1、环境规划

服务器配置:

  • 建议最小配置:2核CPU、2G内存、20G硬盘
  • 最好可以连接外网,方便拉取镜像,不能,提前下载镜像导入节点

软件环境:

软件 版本
Ubuntu ubuntu-20.04.3-live-server-amd64
Docker 目前最新:20.10.12

服务器规划:

主机名 IP
k8s-master-1 192.168.6.31

2、操作系统初始化

1. 配置静态IP

在Ubuntu 20.04上,系统使用“predictable network interface names(可预测的网络接口名称)”标识网络接口。

  1. 识别要配置的以太网接口名称

    ip link
    
  2. 配置分配静态IP

Netplan配置文件存储在/etc/netplan目录中。 您可能会在此目录中找到一个或多个YAML文件。 文件的名称可能因安装程序而异。 通常,文件名为01-netcfg.yaml,50-cloud-init.yaml或NN_interfaceName.yaml

vim /etc/netplan/00-installer-config.yaml
  • :set paste(ubuntu下的vim编辑器粘贴格式可能存在混乱)
# This is the network config written by 'subiquity'
network:
  ethernets:
    ens32:
      dhcp4: false
      addresses:
        - 192.168.6.31/24
      gateway4: 192.168.6.2
      nameservers:
        addresses: [8.8.8.8, 114.114.114.114]
  version: 2

要将静态IP地址分配给ens32接口,请按照以下步骤编辑文件:

  • 将DHCP设置为dhcp4: no。
  • 指定静态IP地址。 在addresses:下,您可以添加一个或多个将分配给网络接口的IPv4或IPv6 IP地址。

  • 指定网关。
  • 在nameservers下,设置以下IP地址: 域名服务器。
  • gateway4地址根据自己的自行修改,我这里之前设置的是2(一般是1)
  1. 保存并应用配置
sudo netplan apply
  1. 验证更改
ip addr show dev ens32
  1. 使用开启root远程连接

    # 设置root密码
    sudo passwd root
       
    # 开启远程登录
    sed -i 's/#PermitRootLogin prohibit-password/PermitRootLogin yes/g' /etc/ssh/sshd_config
       
    sudo systemctl restart ssh
    
  2. 设置时区

    dpkg-reconfigure tzdata
    # 选择Asia -> 再选择Shanghai -> OK
       
    # 或者使用
    cp   /usr/share/zoneinfo/Asia/Shanghai    /etc/localtime
    

    或者直接使用命令:

    timedatectl set-timezone Asia/Shanghai
    
  3. 设置时间格式

    # 需要修改时间为24小时,可以修改/etc/default/locale,默认没有LC_TIME这个变量,在文件中增加一行:
    LC_TIME=en_DK.UTF-8
    # 重启生效
    

2. 初始化操作系统

sudo apt-get update
# 禁用swap分区(修改/etc/fstab,注释掉swap那行,持久化生效)
swapoff -a  # 临时
sed -ri 's/.*swap.*/#&/' /etc/fstab    # 永久

# 主机名规划
hostnamectl set-hostname k8s-master-1

# 同步时间
apt-get install ntpdate -y
ntpdate time.windows.com

# 确保每个机器不会自动suspend(待机/休眠)
sudo systemctl mask sleep.target suspend.target hibernate.target hybrid-sleep.target

Ubuntu开启swap分区:

修改系统的/etc/default/grub文件,修改一下参数(默认为空)

GRUB_CMDLINE_LINUX=”cgroup_enable=memory swapaccount=1”

  1. sudo update-grub命令更新系统
  2. 重启系统

3、安装Docker

官方地址:https://docs.docker.com/engine/install/ubuntu/

1. 卸载旧版本

sudo apt-get remove docker docker-engine docker.io containerd runc

2. 设置存储库

sudo apt-get -y install \
  apt-transport-https \
  ca-certificates \
  curl \
  gnupg \
  lsb-release

3. 添加Docker官方的GPG密钥

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

4. 使用以下命令设置稳定存储库

echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

5. 安装引擎

sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io

如果要安装特定版本如下:

apt-cache madison docker-ce # 列出版本

sudo apt-get install docker-ce=<VERSION_STRING> docker-ce-cli=<VERSION_STRING> containerd.io

# Ubuntu系统安装好像版本号后面需要指定-00
sudo apt-get install docker-ce=20.10.12-00 docker-ce-cli=<VERSION_STRING> containerd.io

6. 验证

docker info

7、配置docker镜像加速

国内从 DockerHub 拉取镜像有时会遇到困难,Docker 官方和国内很多云服务商都提供了国内加速器服务

  • 科大镜像:https://docker.mirrors.ustc.edu.cn/
  • 网易:https://hub-mirror.c.163.com/
  • 阿里云:**https://<你的ID>.mirror.aliyuncs.com**
  • 七牛云加速器:https://reg-mirror.qiniu.com

阿里云镜像获取地址:https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors

sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
  "log-opts": {
    "max-size": "100m",
    "max-file":"5"
  },
  "registry-mirrors": [
    "https://b9pmyelo.mirror.aliyuncs.com",
    "https://3fc19s4g.mirror.aliyuncs.com",
    "https://hub-mirror.c.163.com",
    "https://registry.aliyuncs.com",
    "https://registry.docker-cn.com",
    "https://docker.mirrors.ustc.edu.cn"
  ],
  "insecure-registries": ["https://dockerhub.kubekey.local"],
  "exec-opts": ["native.cgroupdriver=systemd"],
  "data-root": "/data/docker"
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker

5、Docker镜像

镜像不是一个单一的文件,而是有多层构成。我们可以通过docker history <imageID/name> 查看镜像中各层内容及大小,每层 对应着Dockerfile中的一条指令。Docker镜像默认存储在/var/lib/docker/<storage-driver>中。 docker官方镜像仓库 :https://hub.docker.com/explore

img

  • 一个分层存储的文件
  • 一个软件的环境
  • 一种标准化的交付
  • 一个不包含Linux内核而又精简的Linux操作系统

1、Docker镜像和容器的关系

一对多,一个镜像可以创建多个容器

容器其实是在镜像的最上面加了一层读写层,在运行容器里文件改动时, 会先从镜像里将要写的文件复制到容器自己的文件系统中(读写层)。 如果容器删除了,最上面的读写层也就删除了,改动也就丢失了。所以无论多 少个容器共享一个镜像,所做的写操作都是从镜像的文件系统中复制过来操作 的,并不会修改镜像的源文件,这种方式提高磁盘利用率。

若想持久化这些改动,可以通过docker commit 将容器保存成一个新镜像。

2、Docker常用镜像管理命令

指令 描述
ls 列出镜像
build 构建镜像
history 查看镜像历史
inspect 显示一个或多个镜像详细信息
pull 拉取镜像
push 推送镜像
search 搜索镜像
rmi 移除一个或多个镜像
prune 移除未使用的镜像(没有被标记或被任何容器引用的)
tag 创建一个引用源镜像标记目标镜像
export 导出容器文件系统到tar归档文件
import 导入容器文件系统tar归档文件创建镜像
save 保存一个或多个镜像到一个tar归档文件
load 加载镜像来自tar归档或标准输入

3、操作实例

  1. 拉取镜像busybox:1.28.4nginx

    docker pull busybox:1.28.4
    docker pull nginx
    
  2. 导出nginx镜像到/opt/images

    docker save nginx:latest | gzip > /opt/images/nginx-latest.tar.gz
    
  3. 删除镜像nginx

    docker rmi nginx:latest
    
  4. 导出nginx 镜像,文件名为nginx-latest.tar.gz,位于/opt/images

    docker load -i nginx-latest.tar.gz
    

6、Docker容器

1、docker常见的容器管理命令

指令 描述
ls 列出容器
inspect 显示一个或多个容器详细信息
exec 在运行的容器中执行命令
commit 创建一个新镜像来自容器
cp 拷贝文件或文件夹
logs 获取一个容器日志
port 列出或指定容器映射端口
top 显示一个容器运行的进程
stats 显示容器资源使用统计
stop/start/restart 停止/启动一个或多个容器
rm 删除一个或多个容器

2、创建容器是常用的选项

选项 描述
-i, –interactive 交互式
-t, –tty 分配一个伪终端
-d, –detach 后台运行
-e, –env 设置环境变量
-p, –publish list 映射容器端口到主机
-P, –publish-all 映射容器所有EXPOSE的端口到宿主机随机端口
–name string 指定容器名称
-h, –hostname 设置容器主机名
–ip string 指定容器ip,只能用于自定义网络
–network 连接容器到一个网络
-v, –volume list 绑定挂载卷
–restart string 可选值:[always on-failure]

3、资源限制常用选项

选项 描述
-m, –memory 容器使用的最大内存量
–memory-swap 允许交换到磁盘的内存量
–memory-swappiness=<0-100> 容器使用SWAP分区交换的百分比(0-100,默认为-1)
–oom-kill-disable 禁用OOM Killer
–cpus 可以使用的CPU数量
–cpuset-cpus 限制容器使用特定的CPU核心,如(0-3, 0,1)
–cpu-shares CPU共享(相对权重)
  • cpuset-cpus:多个容器竞争同一CPU的时间片时,才会存在竞争现象

4、Docker资源限制

Docker通过linux的Cgroup 来控制容器使用的资源额度,其中有CPU、内存、磁盘等,基本覆盖了常见的资源配额和使用量控制。

防止某个或一些容器占用大量(例如某些服务被黑),影响其他容器的正常运行,资源限制显得尤为重要。

1. Cgroup介绍

cgroups(Control Groups) 是 linux 内核提供的一种机制(Linux 2.6.24内核开始将Cgroup加入主线), 这种机制可以根据需求把一系列系统任务及其子任务整合(或分隔)到按资源划分等级的不同组内,从而 为系统资源管理提供一个统一的框架。简单说,cgroups 主要用于限制和隔离一组进程对系统资源的使 用,也就是做资源QoS。可控制的资源主要包括CPU、内存、block I/O、网络带宽等等。本质上来说, cgroups 是内核附加在程序上的一系列钩子(hook),通过程序运行时对资源的调度触发相应的钩子以达 到资源追踪和限制的目的。

2. stress介绍

stress是一款压力测试工具,可以用它来对系统CPU,内存,以及磁盘IO生成负载。

apt-get install stress

yum -y install epel-release
yum -y install stress

参数解释:

-? 显示帮助信息
-v 显示版本号
-q 不显示运行信息
-n,--dry-run 显示已经完成的指令执行情况
-t --timeout N 指定运行N秒后停止
   --backoff N 等待N微妙后开始运行
-c --cpu 产生n个进程 每个进程都反复不停的计算随机数的平方根
-i --io  产生n个进程 每个进程反复调用sync(),sync()用于将内存上的内容写到硬盘上
-m --vm n 产生n个进程,每个进程不断调用内存分配malloc()和内存释放free()函数
   --vm-bytes B 指定malloc时内存的字节数 (默认256MB)
   --vm-hang N 指示每个消耗内存的进程在分配到内存后转入休眠状态,与正常的无限分配和释放内存的处理相反,这有利于模拟只有少量内存的机器
-d --hadd n 产生n个执行write和unlink函数的进程
   --hadd-bytes B 指定写的字节数,默认是1GB
   --hadd-noclean 不要将写入随机ASCII数据的文件Unlink
    
时间单位可以为秒s,分m,小时h,天d,年y,文件大小单位可以为K,M,G
  1. 对CPU压测

    # 运行两个进程把CPU占满,30s后结束
    stress -c 2 -v -t 30m 
    
  2. 对内存压测

    stress -m 3 --vm-bytes 300M
    
  3. 对磁盘压测

    stress -i 2 -d 4
    

5、操作实例

  1. 使用nginx镜像创建一个名为web的容器,并以后台方式运行以及对外暴露服务(8080)

    docker run -d -p 8080:80 --rm --name web nginx
    
  2. 使用busybox:1.28.4镜像创建名为busybox的容器,以交互式运行

    docker run -it --rm --name busybox busybox:1.28.4
       
    # 指定主机名
    docker run -it -h mytest --rm --name busybox busybox:1.28.4
    
  3. 内存限制

    # 允许容器最多使用100M内存和200M的Swap,并禁用 OOM Killer:
    docker run -it --rm --name test --memory="100m" --memory-swap="200m" --oom-kill-disable geray/centos:v7-1 bash
       
    # 检查
    docker inspect test | grep -i memory
       
    # 查看内存大小(默认单位:Bytes)
    cat /sys/fs/cgroup/memory/memory.limit_in_bytes
    
  4. CPU限制

    # 允许容器最多使用一个半的CPU:
    docker run -d --rm --name nginx01 --cpus="1.5" nginx
    # 允许容器最多使用50%的CPU:
    docker run -d --rm --name nginx02 --cpus=".5" nginx
       
    # 绑定容器到cpu1的核心上,并给定500的权重占比
    docker run -itd --rm --name cpu --cpuset-cpus 1 --cpu-shares 500  geray/centos:v7-1 /bin/bash
       
    # 检查CPU配置
    docker inspect cpu | grep -i cpu
    
  5. 压测CPU:创建容器cpu0cpu1 ,同时绑定在cpu0上,并压测观察(尽管没有占100%权重,一样可以使用100%)

    docker run -itd --rm --name cpu0 --cpuset-cpus 0 --cpu-shares 500  geray/centos:v7-1 bash
    docker run -itd --rm --name cpu1 --cpuset-cpus 0 --cpu-shares 1000  geray/centos:v7-1 bash
       
    # 进入容器安装stress
    docker exec -it cpu0 bash
    yum -y install epel-release
    yum -y install stress
       
    # 压测:运行两个进程把CPU占满,30s后结束
    stress -c 2 -v -t 30m 
    
  6. 内存:

    docker run -it --rm --name memory1 -m 128m geray/centos:v7-1
       
    # 查看内存大小(默认单位:Bytes)
    cat /sys/fs/cgroup/memory/memory.limit_in_bytes 
       
    

    image-20220108194912961

    如果存在警告:未开启swap分区

    image-20220108194055782

    ubuntu或其他基于Debian的系统上才会出现的问题,原因是系统默认未开启swap限制;

    修改系统的/etc/default/grub文件,修改一下参数(默认为空)

    GRUB_CMDLINE_LINUX=”cgroup_enable=memory swapaccount=1”

    1. sudo update-grub命令更新系统
    2. 重启系统
  7. 创建容器limit0 ,只能使用1个CPU核心和128m内存

    docker run -it --rm --name limit0 --cpuset-cpus 1 -m 128m  geray/centos:v7-1 bash
    
  8. 使用mysql:8 镜像练习

docker pull mysql:8

docker run -d --rm --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=12345 mysql:8

docker run -it mysql mysql -h 192.168.6.31 -uroot -p

7、Docker挂载(持久化存储)

  1. 容器中的数据如何存储?
  2. web应用的日志如何存储?如何获取错误日志排查故障?
  • 每一个容器都会有一个相关的挂载(默认位置:/var/lib/docker/overlay2/<容器ID>
  • 容器使用overlay读写

1、储存卷概述

操作系统的目录树是由一组挂载点创建而成,这些挂载点描述了如何能构建出一个或多个文件系统。

存储卷是容器目录树上的挂载点,其中一部分主机目录树已经被挂载了。

如果没有存储卷,Docker 用户会受限于Union文件系统,仅提供镜像挂载。

image-20220109101911193

如上图:容器中运行着的一个程序,正写数据到文件中。

第一个文件写入到了根文件系统。操作系统控制根文件系统将改变的部分装入 Union文件系统的顶层。

第二个文件则写入到已经挂载于容器目录树/data 中。改动会通过存储卷直接影响到主机文件系统上。

虽然Union文件系统适用于构建和分享镜像,但对持久化或共享数据而言,并不是理想的方法。存储卷填补了这些用例,并在容器化系统设计中发挥了关键作用。

存储卷特点:

  • 一个数据分割和共享的工具
  • 与容器无关的范围和生命周期

2、挂载数据到容器

Docker提供三种方式将数据从宿主机挂载到容器中:

  • volumes:Docker管理宿主机文件系统的一部分(/var/lib/docker/volumes)。保存数据的最佳方式。
  • Bind Mounts:将宿主机上的任意位置的文件或者目录挂载到容器中。
  • tmpfs:挂载存储在主机系统的内存中,而不会写入主机的文件系统。如果不希望将数据持久存储在任何位置,可以使用 tmpfs,同时避免写入容器可写层,提高性能。(临时保存到内存中,容器停止tmpfs被删除)

image-20220110135653734

Docker数据卷相关命令docker volume --help

3、volume

  • Docker管理宿主机文件系统的一部分(默认位置:/var/lib/docker/volumes
  • 保存数据的最佳方式。
# 管理卷:
docker volume create nginx1
docker volume create nginx2
docker volume ls
docker volume inspect nginx1
# 用卷创建一个容器:
docker pull geray/nginx:v1.17.10

# 容器数据映射到宿主机
docker run -d --rm -p 8080:80 --name=nginx1 --mount src=nginx1,dst=/usr/local/nginx/html geray/nginx:v1.17.10
docker run -d --rm -p 8081:80 --name=nginx2 -v nginx2:/usr/local/nginx/html geray/nginx:v1.17.10

# 清理:
docker stop nginx1 nginx{1,2}
docker rm nginx1 nginx{1,2}
docker volume rm nginx{1,2} # 删除数据卷

小结:

  1. 如果没有指定卷,自动创建。
  2. 建议使用–mount,更通用。
  3. volume只能存放到docker的特定区域(默认位置:/var/lib/docker/volumes/<volume-name>/_data
  4. docker管理宿主机文件系统的一部分
  5. src数据卷中如果有数据,会将数据映射到容器中,并隐藏容器中原有的数据
  6. src数据卷中如果没有数据,会将容器中的原有数据映射出来

4、Bind Mounts

  • 宿主机任意位置与docker容器映射
  • bind mounts不由docker管理
  • bind mounts可以将宿主机上的任意位置的文件或者目录挂载到容器中
  • volume会将容器中的原有文件映射到宿主机(宿主机原位置是否存在文件?),bind mounts会将宿主机数据映射到容器(隐藏原有容器的源文件)
  • 格式:--mount type=bind,src=源目录,dst=目标目录
# 挂载目录:
docker run -d -it -p 8083:80 --name=nginx3 --mount type=bind,src=/tmp/nginx3,dst=/usr/local/nginx/html geray/nginx:v1.17.10
# /tmp/nginx3必须存在

docker run -d -it -p 8084:80 --name=nginx4 -v /tmp/nginx4:/usr/local/nginx/html geray/nginx:v1.17.10

# 挂载文件
docker run -d -it -p 8085:80 --name=nginx5 -v /tmp/nginx5/index.html:/usr/local/nginx/html/index.html geray/nginx:v1.17.10

docker run -d -it -p 8086:80 --name=nginx6 --mount type=bind,src=/tmp/nginx6/index.html,dst=/usr/local/nginx/html/index.html geray/nginx:v1.17.10

# 验证绑定:
docker inspect <container-name>

# 清理:
docker stop nginx{1..6}
docker rm nginx{1..6}
rm -rf /tmp/nginx{1..6}

小结:

目录:

  1. 使用mount挂载目录时,src源目录必须存在(否则抛出错误信息)
  2. 使用-v挂载目录时,src源目录不存在会自动创建

文件:

  1. mount-v挂载文件,src源文件必须存在,否则抛出错误信息:bind source path does not exist: <文件路径>.
  • bind Mount无论src源位置中是否存在数据,都会隐藏容器中原有数据

5、Volume VS Bind Mounts总结

  • 使用-v参数挂载时,:前如果是路径则是bind mounts方式,否则是volume方式
  • 两种方式挂载时,如果宿主机目录中存在数据,则会覆盖容器中原有的数据

Volume:

  1. 如果没有指定卷,自动创建。
  2. 多个运行容器之间共享数据,多个容器可以同时挂载相同的卷。
  3. volume只能存放到docker的特定区域(默认位置:/var/lib/docker/volumes/<volume-name>/_data
  4. docker管理宿主机文件系统的一部分(当容器停止或被移除时,该卷依然存在;明确删除卷时,卷才会被删除。 )
  5. src数据卷中如果有数据,会将数据映射到容器中,并隐藏容器中原有的数据
  6. src数据卷中如果没有数据,会将容器中的原有数据映射出来
  7. 将容器的数据存储在远程主机或其他存储上(间接)
  8. 将数据从一台Docker主机迁移到另一台时,先停止容器,然后备份卷的目录(/var/lib/docker/volumes/)

Bind Mounts

  1. 使用mount挂载目录时,src源目录必须存在(否则抛出错误信息)

  2. 使用-v挂载目录时,src源目录不存在会自动创建

  3. mount-v挂载文件,src源文件必须存在,否则抛出错误信息:bind source path does not exist: <文件路径>.

  4. bind Mount无论src源位置中是否存在数据,都会隐藏容器中原有数据(错误描述)

6、tmpfs

tmpfs是Linux/Unix系统上的一种基于内存的虚拟文件系统。tmpfs可以使用您的内存或swap分区来存储文件(即它的存储空间在virtual memory 中, VM由real memory和swap组成)。由此可见,tmpfs主要存储暂存的文件。

特点:

  1. 动态文件系统的大小。
  2. tmpfs 使用VM建的文件系统,速度当然快。
  3. 重启后数据丢失。

实际应用中,为应用的特定需求设定此文件系统,可以提升应用读写性能,如将squid 缓存目录放在/tmp, php session 文件放在/tmp, socket文件放在/tmp, 或者使用/tmp作为其它应用的缓存设备

如果Docker位于Linux操作系统上,可以使用tmpfs mounts。使用tmpfs挂载创建容器时,容器可以在容器的可写层外创建文件。

与volume和绑定挂载相反,tmpfs挂载是临时的,并且仅保留在主机内存中。当容器停止后,将tmpfs删除安装,并且不会保留写在那里的文件。

  • tmpfs无法实现容器间共享
  • 只有在Linux上运行Docker时才能使用此功能

tmpfs使用(没有src)

  • --tmpfs标志不允许您指定任何可配置选项。
  • --tmpfs标志不能与swarm服务一起使用。你必须使用--mount

使用tmpfs挂载的两种方式

  1. --tmpfs标志
  2. --mount带有type=tmpfsdestination选项的 标志
# --mount type=tmpfs方式
docker run -itd --name nginx-tmpfs1 --mount type=tmpfs,dst=/usr/local/nginx/app geray/nginx:v1.17.10

# --tmpfs方式
docker run -itd --name nginx-tmpfs2 --tmpfs /usr/local/nginx/app geray/nginx:v1.17.10

docker stop nginx-tmpfs{1,2}
docker rm nginx-tmpfs{1,2}

指定tmpfs选项:

选项 描述
tmpfs-size tmpfs的大小以字节为单位。默认无限制。
tmpfs-mode 八进制中tmpfs的文件模式。例如,7000770。默认为1777或全局可写。
# 使用tmpfs挂载,并设置容器不是全局可读
docker run -d -it \
     --name tmptest \
     --mount type=tmpfs,dst=/usr/local/nginx/app,tmpfs-mode=1770 \
     geray/nginx:v1.17.10

7、操作实例

  1. 创建名为tomcat的volume数据卷

    docker volume create tomcat
    
  2. 使用geray/tomcat9:latest镜像创建容器

    • 容器名:tomcat

    • 将容器的端口映射到宿主机上的8080端口

    docker pull geray/tomcat9:latest
       
    docker inspect geray/tomcat9:latest | grep -A2 -i ExposedPorts
       
    docker run -d --name tomcat -p 8080:8080 geray/tomcat9:latest
    
  3. 使用geray/tomcat9:latest镜像创建tomcat1容器,对外暴露端口8081

    1. 使用上面创建的tomcat卷挂载镜像的日志目录
    2. 使用volume方式挂载容器中的配置文件到tomcat-conf数据卷
    3. 使用bind mounts方式挂载tomcat的项目路径到/tmp/tomcat/webapps
    4. 通过宿主机修改index.html并访问
    mkdir -p /tmp/tomcat/webapps
       
    docker run -d \
    	--name tomcat1 -p 8081:8080 \
    	--mount type=volume,src=tomcat,dst=/usr/local/tomcat/logs \
    	-v tomcat-conf:/usr/local/tomcat/conf \
    	--mount type=bind,src=/tmp/tomcat/webapps,dst=/usr/local/tomcat/webapps \
    	geray/tomcat9:latest
    
  4. 清理环境

    for i in $(docker ps -a | awk '{print $1}');do docker stop $i && docker rm $i;done
       
    docker volume prune
    rm -rf /tmp/tomcat
    

8、Docker网络

# 查看是否开启IPv4转发
sysctl net.ipv4.ip_forward

# 开启IPv4网络转发功能
sed -i 's/#net.ipv4.ip_forward=1/net.ipv4.ip_forward=1/g' /etc/sysctl.conf
sysctl -p /etc/sysctl.conf

# 重启网络服务(CentOS)
systemctl restart network

Docker的4种网络模型:

  • bridge:使用--net=bridge指定(默认)。

    默认网络,Docker启动后创建一个docker0网桥,默认创建的容器也是添加到这个网桥中。

    docker run -itd --net=bridge --name=net1 geray/nginx:v1.17.10
    
  • host:使用--net=host指定。

    容器不会获得一个独立的network namespace,而是与宿主机共用一个。这就意味着容器不会有自己的网卡信息(端口映射也会不生效),而是使用宿主机的。容器除了网络,其他都是隔离的。

    docker run -it --net=host --name=net2 geray/nginx:v1.17.10 bash
    
  • none:使用--net=none指定。

    获取独立的network namespace,但不为容器进行任何网络配置,需要我们手动配置。

    docker run -it --net=none --name=net3 geray/nginx:v1.17.10 bash
    

    挂在这个网络下的容器除了 lo,没有其他任何网卡(感兴趣的可以借助pipework配置IP)

  • container:使用--net=container:<NAME_or_ID>指定。

    与指定的容器使用同一个network namespace,具有同样的网络配置信息,两个容器除了网络,其他都还是隔离的。

    docker run -it --net=container:net1 --name=net4 geray/nginx:v1.17.10 bash
    
  • 自定义网络

    与默认的bridge原理一样,但自定义网络具备内部DNS发现,可以通过容器名容器之间网络通信。

Docker网络相关命令docker network --help

# 清理环境
docker stop net{1..4}
docker rm net{1..4}

1、操作实例

  1. 创建一个名为mysql的网络,并使用bridge模式

    docker network create mysql --driver=bridge
    
  2. 使用MySQL官方镜像及说明创建MySQL容器并测试连接(并进行挂载测试)

    # 创建mysql容器,并使用docker的mysql网络
    docker run -d --name mysql \
    	-h test \
    	--net=mysql \
    	-p 3306:3306 \
    	-v /tmp/mysql:/var/lib/mysql \
    	-e MYSQL_ROOT_PASSWORD=12345 \
        mysql:8
       
    # 创建一个同网络的容器并连接
    docker run -it --name test --rm mysql:8 mysql -h172.23.0.1 -uroot -p
    
  3. 删除上面创建的网络和容器

    docker stop mysql test
    docker rm mysql test
    docker network prune
    docker volume prune
    

9、Dockerfile

1、构建镜像的原则

  • 小巧安全、适当复用

尽量选择小的基础镜像,避免安装不必要的软件包、减少镜像层数、最小化容器权限

Linux操作系统的基础镜像:

镜像名称 大小 使用场景
busybox 1.15MB 临时测试用
alpine 4.41MB 主要用于测试,也可用于生产环境
centos 200MB 主要用于生产环境,支持CentOS/Red
ubuntu 81.1MB 主要用于生产环境,常用于人工智能计算和企业应用
debian 101MB 主要用于生产环境

2、Dockerfile命令说明

指令 描述
FROM 基准镜像
MAINTAINER(已弃用) 镜像维护者姓名和邮箱地址
LABEL 设置标签比MAINTAINER更强大
RUN 构建镜像时运行的shell命令
COPY 拷贝数据到镜像
ENV 设置环境变量
USER 设置用户名或UID
EXPOSE 声明容器运行的服务端口
HEALTHCHECK 容器中服务健康检查
VOLUME 声明挂载路径
WORKDIR 设置工作目录
ENTRYPOINT 设置默认命令,运行容器时执行,多个指令时最后一个生效
CMD 设置ENTRYPOINT参数,运行容器时执行,多个CMD指令时最后一个生效

3、CentOS基础镜像构建实例

更多功能的CentOS基础镜像

  • locale -a 不支持中文语言
FROM centos:7
MAINTAINER "Geray <1690014753@qq.com>"
#LABEL geray=1690014753@qq.com

RUN yum -y install kde-l10n-Chinese && \
  yum -y reinstall glibc-common && \
  yum clean all && \ 
  rm -rf /var/cache/yum/* && \
  localedef -c -f UTF-8 -i zh_CN zh_CN.utf8 && \
  echo "LC_ALL=\"zh_CN.UTF-8\"" > /etc/locale.conf
  
#env 
ENV TZ "Asia/Shanghai" 
#ENV LANG en_US.UTF-8  
ENV LANG zh_CN.UTF-8 
  • kde-l10n-Chinese:中文语言包
  • yum -y reinstall glibc-common 更新包(防止镜像不能成功加载语言包)
  • localedef -c -f UTF-8 -i zh_CN zh_CN.utf8设置系统语言

image-20220111102616989

构建并导出镜像练习

docker build -t <image-name>:<label> .
# 注意后面的. 表示当前路径(Dockerfile的目录里)
# 如果Dockerfile不在当前目录下,可以使用-f 指定
# 构建
docker build -t centos7:latest .
# 导出
docker save centos7:latest | gzip > cnetos7-latest.tar.gz
# 删除镜像并根据导出的文件导入镜像
docker rmi centos7:latest

docker load -i cnetos7-latest.tar.gz

3、镜像优化

  1. 尽量避免不必要的软件包

    降低复杂性并减少依赖;比如:开发调试所需的软件包

  2. 尽量减少镜层数

    便于维护并减小镜像大小,比如软件包的安装命令放到同一个RUN中,避免将缓存提交到镜像中

    yum install 和 yum clean 放在同一个 RUN 指令中

  3. 选择最小的基础镜像

  4. 最小权限原则运行应用程序

  5. 利用缓存加速构建

    docker build 按照 Dockerfile 中指令的顺序逐个执行,并把每个指令的构建结果缓存起来,这样下次构建的时候就可以进行复用;尽量把很少变化的指令放到前面,而经常变化的指令(比如 COPY 和 CMD)放到后面。

4、.dockerignore使用

作用:

  • 防止无用文件被复制到镜像中

方式1:指定需要被复制的文件

cat .dockerignore
*
! file1
! /opt/file2
  • "*"表示的意思是把所有目录或文件都拒绝了
  • "!"表示被接受的路径或文件

方式2:指定不需要被复制的文件

cat .dockerignore
mailer-base.d
fmailer-logging.d
fmailer-live.df

image-20220113164109378

5、多阶段构建(multi-stage builds)

1. 构建原理

多阶段构建通过在Dockerfile中使用多个 FROM指令实现。每一条 FROM 指令都是一个构建阶段,多个 FROM指令就是多阶段构建。

多阶段构建的意义在于:在构建的过程中,可以选择性的将前面阶段中必要的文件复制到后面的阶段中,并抛弃不需要的文件。这样,最后的镜像中只保留需要的文件(减少镜像大小)。

2. 实例

  • hello.go
package main

import (
        "fmt"
        "runtime"
)

func main() {
	fmt.Println("多阶段镜像构建测试")
	fmt.Printf("Hello, %s!\n", runtime.GOARCH)
}
  • Dockerfile
FROM golang:1.13.5
WORKDIR /go/src/github.com/helloworld/
# RUN go get -d -v golang.org/x/net/html  # 官方实例中使用的代理
# go get命令——一键获取代码、编译并安装
# -d 只下载不安装
# -v 显示执行的命令
RUN go get -d -v github.com/go-sql-driver/mysql
COPY hello.go .
# 编译go
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o hello .

# 镜像构建
FROM alpine:latest
LABEL geray=1690014753@qq.com \
    	author=Geray \
    	TIME=2022.9.13
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=0 /go/src/github.com/helloworld/hello .
CMD ["./hello"]

当CGO_ENABLED=1, 进行编译时, 会将文件中引用libc的库(比如常用的net包),以动态链接的方式生成目标文件。 当CGO_ENABLED=0, 进行编译时, 则会把在目标文件中未定义的符号(外部函数)一起链接到可执行文件中。

GOOS=linux 编译成linux可执行的二进制文件。

  • 构建
docker build -t geray/hello:v1 .

3. AS 阶段命名

FROM golang:1.13.5 as builder
WORKDIR /go/src/github.com/helloworld/
# RUN go get -d -v golang.org/x/net/html  # 官方实例中使用的代理
# go get命令——一键获取代码、编译并安装
# -d 只下载不安装
# -v 显示执行的命令
RUN go get -d -v github.com/go-sql-driver/mysql
COPY hello.go .
# 编译go
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o hello .

# 镜像构建
FROM alpine:latest
LABEL geray=1690014753@qq.com \
    	author=Geray \
    	TIME=2022.9.13
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /go/src/github.com/helloworld/hello .
CMD ["./hello"]

4. –target 指定阶段构建

可以使用 –target构建指定阶段的镜像,该阶段镜像构建完即停止。

构建上面两个阶段中的第一个:builder

docker build --target builder -t geray/hello:target_builder .

5. COPY –from 从其他镜像复制文件

可以使用COPY –from指令从其他镜像(如前面阶段构建的镜像,本地镜像,Docker Hub上的镜像)

FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=hello:target_builder /go/src/github.com/helloworld/hello .
CMD ["./hello"]

构建

docker build -t geray/hello:builder-from .

6、构建不同架构的镜像

cpu1

我们来简单看下以下的常见的四大主流芯片架构:

cpu2

ARM和X86架构最显著的差别是使用的指令集(复杂指令集)不同,RiSC-V架构与MIPS架构是一种采取精简指令集(RISC)的处理器架构。

1. 跨 CPU 架构编译程序的不同方法

方式1 - 直接在目标硬件上编译

如果我们可以访问目标架构硬件,同时该操作系统支持运行构建所需的各种工具,那么就可以直接在硬件上编译应用程序。

方式2 - 模拟目标硬件

QEMU是一套由法布里斯·贝拉(Fabrice Bellard)所编写的以GPL许可证分发源码的模拟处理器软件,在GNU/Linux平台上使用广泛。

Bochs,PearPC等与其类似,但不具备其许多特性,比如高速度及跨平台的特性,通过KQEMU这个闭源的加速器,QEMU能模拟至接近真实电脑的速度。

方式3 - 模拟目标硬件的用户空间

在 Linux 系统上,QEMU 有另外一种操作模式,可以通过用户模式模拟器来运行非本地架构的二进制程序。

该模式下,QEMU 会跳过方法 2 中描述的对整个目标系统硬件的模拟,取而代之的是通过 binfmt_misc 在 Linux 内核注册一个二进制格式处理程序,

将陌生二进制代码拦截并转换后再执行,同时将系统调用按需从目标系统转换成当前系统。

最终对于用户来说,他们会发现可以在本机运行这些异构二进制程序。

通过 QEMU 的用户态模式,我们可以创建轻量级的虚拟机(chroot 或容器),然后在虚拟机系统中编译程序,和本地编译一样简单轻松。

跨平台构建 Docker 镜像用的就是这个方法。

方法4 - 使用交叉编译器

一种在嵌入式系统社区标准的做法:交叉编译。

交叉编译器是专门为在给定的系统平台上运行而设计的编译器,但是可以编译出另一个系统平台的可执行文件。

例如,amd64 架构的 Linux 系统上的 C++ 交叉编译器可以编译出运行在 aarch64(64-bit ARM) 架构的嵌入式设备上的可执行文件。安卓设备的 APP 基本上都是通过这种方法来编译的。

从性能角度来看,该方法与方法 1 没什么区别,因为不需要模拟器的参与,几乎没有性能损耗。

但交叉编译不具有通用性,它的复杂度取决于程序使用的语言。如果使用 Golang 的话,那就超级简单。

在云原生容器时代,我们讨论构建时不仅包括构建单个可执行文件,还包括构建容器镜像。

而且构建容器镜像比上面说的方法更复杂,再加上 Docker 本身的复杂性,这是一个很复杂的问题。

为了能够更方便的构建多架构 Docker 镜像,我们可以使用最近发布的 Docker 扩展:buildx。

buildx 是下一代标准 docker build 命令的前端,既我们熟悉的用于构建 Docker 镜像的命令。

通过借助 BuildKit ,buildx 扩展了表中 docker build 命令的功能,成为 Docker 构建系统的新后端。

docker manifest create合并多架构镜像推送到私有仓库
docker pull nginx:latest --platform linux/arm64
docker tag nginx:latest repos.cloud.cmft/ruoyi/nginx:latest-arm64
docker push repos.cloud.cmft/ruoyi/nginx:latest-arm64

docker pull nginx:latest --platform linux/amd64
docker tag nginx:latest repos.cloud.cmft/ruoyi/nginx:latest-amd64
docker push repos.cloud.cmft/ruoyi/nginx:latest-amd64

# 需要先push tag后的镜像到私有仓库,遇到证书问题可以使用insecure进行忽略

docker images | grep nginx

docker manifest create repos.cloud.cmft/ruoyi/nginx:latest repos.cloud.cmft/ruoyi/nginx:latest-arm64 repos.cloud.cmft/ruoyi/nginx:latest-amd64
docker manifest push repos.cloud.cmft/ruoyi/nginx:latest  --insecure

参考链接:https://www.zhaowenyu.com/docker-doc/reference/dockercmd/dockercmd-manifest-create.html

2. 启用buildx插件

Docker 版本不低于 19.03

开启buildx 功能 默认情况下,buildx已经在安装包里面了 在 ~/.docker/config.json增加,是家目录的client端的配置不是/etc下的服务端配置 "experimental": "enabled" 即可永久开启buildx命令 为了良好的支持性,如果是centos版本需要升级内核到5.12.9才能正常使用 centos7内核升级

下载插件

mkdir -pv ~/.docker/cli-plugins/
wget -O ~/.docker/cli-plugins/docker-buildx \
    https://github.com/docker/buildx/releases/download/v0.5.1/buildx-v0.5.1.linux-amd64

chmod a+x ~/.docker/cli-plugins/docker-buildx 

启用插件

cat ~/.docker/config.json 
{
        "auths": {
                "https://index.docker.io/v1/": {
                        "auth": "Z2VyYXk6R2VyYXkmTGkxMTM="
                },
                "registry.cn-hangzhou.aliyuncs.com": {
                        "auth": "MTczMzk4NzIxNjU6R2VyYXlAMjAyMg=="
                }
        }
}
{
    "experimental": "enabled"
}

systemctl restart docker
docker buildx version

linux系统需要设置binfmt_misc,否则没有缺少很多架构,其他系统默认已开启

# 创建实例
docker buildx create --name mybuilder --driver docker-container
# 使用实例
docker buildx use mybuilder
# 查看已有实例
docker buildx ls
# 安装模拟器(用于多平台镜像构建)
docker run --rm --privileged tonistiigi/binfmt:latest --install all
# 或者使用
docker run -d --name binfmt --rm --privileged docker/binfmt:66f9012c56a8316f9244ffd7622d7c21c1f6f28d


# 查看支持其他架构的镜像的运行环境
docker buildx inspect --bootstrap    
# 或者
ls /proc/sys/fs/binfmt_misc/qemu-*

3. 构建支持多个架构的镜像

这是一个多阶段构建 Dockerfile,使用 Go 编译器来构建应用,并将构建好的二进制文件拷贝到 alpine 镜像中。

buildx 构建一个支持 arm、arm64 和 amd64 多架构的 Docker 镜像。

FROM golang:1.13.5
 
LABEL maintainer xcbeyond
 
WORKDIR /app

COPY hello.go /app
RUN go build -o hello /app/hello.go
 
CMD ["./hello"]

构建镜像并上传

# 登陆dockerhub
docker login -ugeray

# 构建镜像并上传到镜像仓库
docker buildx build -t geray/hello:buildx-v1 --platform=linux/arm,linux/arm64,linux/amd64 --push .

4. 模拟arm架构系统

https://blog.csdn.net/xiang_freedom/article/details/92724299

docker开启manifest功能

~/.docker/config.json 中添加参数

{
  "auth": {},
  "experimental": "enabled"   
}

/etc/docker/daemon.json中添加参数

{
  "registry-mirrors": [
    "https://hub-mirror.c.163.com",
    "https://mirror.baidubce.com",
    "https://docker.mirrors.ustc.edu.cn",
    "https://3fc19s4g.mirror.aliyuncs.com"
  ],
  "experimental": true
}

重启docker服务

systemctl daemon-reload
systemctl restart docker
# 检查是否开启
docker manifest

#查看docker是否开启experimental功能
docker version 

拉取镜像测试

# 下载arm镜像
docker pull arm64v8/ubuntu
docker pull arm32v7/ubuntu:18.04

docker run -it -v /usr/bin/qemu-aarch64-static:/usr/bin/qemu-aarch64-static --name arm_test --rm arm64v8/ubuntu bash

docker run -it -v /usr/bin/qemu-aarch64-static:/usr/bin/qemu-aarch64-static --name arm_test --rm arm32v7/ubuntu:18.04 bash

5. 获取不同架构的镜像并测试脚本

# 查看镜像架构信息
docker manifest inspect --insecure geray/hello:buildx-v1

# 拉取指定架构的镜像
docker pull --platform=arm64 geray/hello:buildx-v1

# 打包后解压出hello脚本
docker save -o hello.tar geray/hello:buildx-v1

# 解压tar文件
tar xf hello.tar

# 查看manifest.json可以看到具体哪个layer是最新的。
# 找其中一个layer再解压
cd <层>
tar xf layer.tar

# 模拟arm架构服务运行脚本
docker run -it --name arm_test --rm arm64v8/ubuntu bash

docker cp hello arm_test:/
docker exec -it arm_test bash /hello

7、manifest构建多架构镜像到私有仓库

1.命令操作

  • 操作过程
    首先,推送每个架构对应的镜像:
    bash复制代码
    docker push your-image:tag-amd64
    docker push your-image:tag-arm64
    然后,创建镜像清单:
    bash复制代码
    docker manifest create --insecure your-image:tag \
    --amend your-image:tag-amd64 \
    --amend your-image:tag-arm64
    推送清单到 Docker Hub:
    bash复制代码
    docker manifest push  --insecure your-image:tag
    这会创建一个多架构镜像标签,Docker 会根据主机的架构自动选择适当的镜像版本。
    
  • 例如 ```

    拉取镜像并使用架构版本后缀构建tag,并推送至镜像仓库(同一镜像仓库的同一个镜像,使用不同架构后缀区分)

    docker pull birdhk/fluid-csi:v0.9.1-16937652 –platform linux/arm64 docker tag birdhk/fluid-csi:v0.9.1-16937652 repos-yltest-mgmt.cloud.test/fluidcloudnative/fluid-csi:v0.9.1-16937652-arm64

docker pull birdhk/fluid-csi:v0.9.1-16937652 docker tag birdhk/fluid-csi:v0.9.1-16937652 repos-yltest-mgmt.cloud.test/fluidcloudnative/fluid-csi:v0.9.1-16937652-amd64

docker push repos-yltest-mgmt.cloud.test/fluidcloudnative/fluid-csi:v0.9.1-16937652-arm64 docker push repos-yltest-mgmt.cloud.test/fluidcloudnative/fluid-csi:v0.9.1-16937652-amd64

- 使用manifest构建并推送

docker manifest create –insecure repos-yltest-mgmt.cloud.test/fluidcloudnative/fluid-csi:v0.9.1-16937652 repos-yltest-mgmt.cloud.test/fluidcloudnative/fluid-csi:v0.9.1-16937652-arm64 repos-yltest-mgmt.cloud.test/fluidcloudnative/fluid-csi:v0.9.1-16937652-amd64 docker manifest push –insecure repos-yltest-mgmt.cloud.test/fluidcloudnative/fluid-csi:v0.9.1-16937652


#### 脚本程序

package main

import ( “fmt” “io/ioutil” “log” “os” “os/exec”

"gopkg.in/yaml.v3" )

type Config struct { Images []string yaml:"images" Harbor struct { URL string yaml:"url" Repository string yaml:"repository" Username string yaml:"username" Password string yaml:"password" InsecureSkipVerify bool yaml:"insecureSkipVerify" } yaml:"harbor" }

func main() { // 读取配置文件 configFile := “manifest-images.yaml” // 默认文件 if len(os.Args) > 1 { configFile = os.Args[1] }

data, err := ioutil.ReadFile(configFile)
if err != nil {
	log.Fatalf("读取配置文件失败: %v", err)
}

// 绑定YAML配置到结构体
var config Config
err = yaml.Unmarshal(data, &config)
if err != nil {
	log.Fatalf("解析 YAML 失败: %v", err)
}

// fmt.Println(config.Harbor.URL)
// fmt.Println(config.Harbor.Repository)
// fmt.Println(config.Harbor.Username)
// fmt.Println(config.Harbor.Password)
// fmt.Println(config.Harbor.InsecureSkipVerify)

// 处理每个镜像
for _, image := range config.Images {
	processImage(image, config)
} }

func processImage(image string, config Config) { arm64Tag := fmt.Sprintf(“%s/%s/%s-arm64”, config.Harbor.URL, config.Harbor.Repository, image) amd64Tag := fmt.Sprintf(“%s/%s/%s-amd64”, config.Harbor.URL, config.Harbor.Repository, image)

// 拉取、标记并推送 arm64 镜像
execCommand("docker", "pull", image, "--platform", "linux/arm64")
execCommand("docker", "tag", image, arm64Tag)
execCommand("docker", "push", arm64Tag)

// 拉取、标记并推送 amd64 镜像
execCommand("docker", "pull", image, "--platform", "linux/amd64")
execCommand("docker", "tag", image, amd64Tag)
execCommand("docker", "push", amd64Tag)

// 创建并推送 manifest
manifestCmd := []string{
	"manifest", "create",
	"--insecure",
	fmt.Sprintf("%s/%s/%s", config.Harbor.URL, config.Harbor.Repository, image),
	arm64Tag,
	amd64Tag,
}
execCommand("docker", manifestCmd...)
pushManifestCmd := []string{
	"manifest", "push",
	"--insecure",
	fmt.Sprintf("%s/%s/%s", config.Harbor.URL, config.Harbor.Repository, image),
}
execCommand("docker", pushManifestCmd...) }

func execCommand(name string, args …string) { cmd := exec.Command(name, args…) cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr err := cmd.Run() if err != nil { log.Fatalf(“命令 %s 执行失败: %v”, name, err) } }


- 配置文件如下:

cat manifest-images.yaml images:

  • birdhk/fluid-csi:v0.9.1-16937652
  • nginx:1.21.0 harbor: url: repos-yltest-mgmt.cloud.test repository: fluidcloudnative username: admin password: xxxx insecureSkipVerify: true

![image](https://github.com/user-attachments/assets/c3f2d6de-2ad2-4665-8bf7-e739eebb2e3a)



### 8、操作实例(搭建wordpress博客为例)

docker pull wordpress docker pull mysql:8

1、创建Mysql容器 docker run -d –name mysql -p 3306:3306
-v mysql-data:/var/lib/mysql
-e MYSQL_ROOT_PASSWORD=root
-e MYSQL_DATABASE=wordpress
mysql:8 –character-set-server=utf8

2、启动项目(–link到那个容器) docker run -d -p 8080:80
–name wordpess
-e WORDPRESS_DB_HOST=192.168.6.31:3306
-e WORDPRESS_DB_USER=root
-e WORDPRESS_DB_PASSWORD=root
wordpress


访问测试:192.168.6.31:8080

![image-20220111141832400](/images/posts/Docker-base/image-20220111141832400.png)

## 10、镜像仓库Harbor

有时候使用 Docker Hub 这样的公共仓库可能不方便,用户可以创建一个本地仓库供私人使用。

常见的有两种:registry 和Harbor

### 1、registry

Registry是Docker的开源项目,主要用于创建个人仓库

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

上传镜像到仓库

docker tag busybox:1.28.4 127.0.0.1:5000/busybox:v1 docker push 127.0.0.1:5000/busybox:v1

用 curl 查看仓库中的镜像。

curl 127.0.0.1:5000/v2/_catalog




### 2、Harbor介绍

Harbor是构建企业级私有docker镜像的仓库的开源解决方案,它是Docker Registry的更高级封装,它除了提供友好的Web UI界面,角色和用户权限管理,用户操作审计等功能外,它还整合了K8s的插件(Add-ons)仓库。

**Harbor安装有3种方式: **

- 在线安装:从Docker Hub下载Harbor相关镜像,因此安装软件包非常小 
- 离线安装:安装包包含部署的相关镜像,因此安装包比较大 
- OVA安装程序:当用户具有vCenter环境时,使用此安装程序,在部署OVA后启动Harbor

### 3、Harbor部署(离线)

下载地址:https://github.com/goharbor/harbor/releases

#### 1. 安装docker-compose

获取地址:https://github.com/docker/compose/releases

Compose是一个用来定义和运行复杂应用的Docker工具。

Compose 通过一个配置文件来管理多个Docker容器,在配置文件中,所有的容器通过services来定义,然后使用docker-compose脚本来启动,停止和重启应用,和应用中的服务以及所有依赖服务的容器,非常适合组合使用多个容器进行开发的场景。

curl -L “https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)” -o /usr/local/bin/docker-compose

chmod +x /usr/local/bin/docker-compose

docker-compose –version


#### 2. 解压配置

tar xf harbor-offline-installer-v2.4.1.tgz -C /opt

配置

cp harbor.yml.tmpl harbor.yml


**harbor.yml详解:**

https://goharbor.io/docs/2.0.0/install-config/configure-yml-file/#required-parameters

hostname设置访问地址,可以使用ip、域名,不可以设置为127.0.0.1或localhost

hostname: 192.168.6.31

HTTP相关配置(不要在生产环境中使用)

http: port: 80 # HTTP 的端口号,用于 Harbor 门户和 Docker 命令。默认值为 80。

HTTPS相关配置(需要证书可以先注释)

#https:

port: 443

certificate: /your/certificate/path # SSL 证书的路径。

private_key: /your/private/key/path # SSL 密钥的路径。

取消以下注释,harbor组件之间将使用TLS通信

internal_tls:

# set enabled to true means internal tls is enabled

enabled: true

# put your cert and key files on dir

dir: /etc/harbor/tls/internal

为 Harbor 系统管理员设置初始密码。该密码仅在Harbor 首次启动时使用。后续登录时,将忽略此设置,并在 Harbor Portal 中设置管理员密码。默认用户名和密码是admin和Harbor12345

harbor_admin_password: Harbor12345

使用本地 PostgreSQL 数据库。您可以选择配置外部数据库

database: password: root123 max_idle_conns: 100 # 空闲连接池中的最大连接数。如果设置为 <=0,则不保留空闲连接。默认值为 50。如果未配置,则值为 2。 max_open_conns: 900 # 与数据库的最大打开连接数。如果 <= 0,则打开连接的数量没有限制。对于到 Harbor 数据库的最大连接数,默认值为 100。如果未配置,则值为 0。

目标主机上存储 Harbor 数据的位置。即使删除和/或重新创建 Harbor 的容器,该数据也保持不变。

data_volume: /opt/harbor/data

配置 Trivy 扫描仪

trivy: ignore_unfixed: false # 将标志设置为true仅显示已修复的漏洞。默认值为false skip_update: false insecure: false

jobservice: max_job_workers: 10

设置 web hook 作业的最大重试次数。默认值为 10。

notification: webhook_job_max_retry: 10

chart: absolute_url: disabled

配置日志记录。Harbor 使用 rsyslog 来收集每个容器的日志。

log: level: info local: rotate_count: 50 rotate_size: 200M location: /opt/harbor/logs

_version: 2.4.0

配置要由 Clair、复制作业服务和 Harbor 使用的代理。

proxy: http_proxy: https_proxy: no_proxy: components: - core - jobservice - trivy

#### 3、安装启动

创建所需的目录

mkdir -p /opt/harbor/{data,logs}

./install.sh


#### 4、验证并访问

docker-compose ps


![image-20220111145732065](/images/posts/Docker-base/image-20220111145732065.png)

访问:IP:80(默认用户名和密码是admin和Harbor12345)



#### 5、Harbor的基本使用

**登陆方式:**`docker login -u admin -p Harbor12345 http://127.0.0.1`

关闭harbor

docker-compose down -v

启动harbor

docker-compose up -d

```

新建项目并上传下载测试

6、Harbor高可用

参考连接:https://www.yuque.com/docs/share/8f8d1f9d-ae30-46fa-84d2-6845d1075a15?#