如今的 IT 企业已逐渐从以 ESB 为中心的面向服务架构过渡到微服务架构。前端工程师需要学会将项目构建为镜像提交,后端工程师需要能够容器化构建和部署软件,运维人员需要设计新的微服务运维架构,小型企业需要依靠云原生平台减少生产成本,中大型企业需要将内部私有云平台升级以支持微服务。。。Docker 作为目前各大公有和私有云平台中最常使用的容器技术,值得所有 IT 技术领域从业人员深入学习。
简而言之,Docker 的出现是为了解决开发、测试和生产环境间存在的差异性,以减少过程成本,使得项目能够快速部署上线,而不需要花过多时间在环境配置和迁移上。即,通过软件带环境安装减少各平台间差异性的影响。
“一次构建,处处运行。” Docker 是解决了运行环境和配置问题的软件容器,方便做持续集成并有助于整体发布的容器虚拟机。
虚拟机是带环境安装的一种解决方案,传统的虚拟机在操作系统中运行另外一些操作系统。传统虚拟机的主要问题在于:
传统虚拟机模拟了所有软件层面的资源,这是没有必要的。实际上,依赖于操作系统的软件需要的只是操作系统的一些内核服务。
Linux 容器(Linux Container,LXC)是 Linux 上的另一种虚拟化服务,该容器本质上是一系列和其他进程与资源所隔离的进程,而不是一个完整的操作系统,只拥有软件需要的资源,即是最小化的操作系统。
Docker 容器是内核级虚拟化技术,只负责虚拟化软件所必须依赖的系统内核服务。Docker 作为容器技术的一种,与虚拟机支撑的操作系统有如下区别和优势:
简而言之,容器更轻量,更迅速。
Docker 容器技术实际上促成了新的岗位:开发/运维工程师(DevOps Engineer)的出现。由于容器技术降低了整个过程的成本, 软件工程师可以直接参与容器层的简单运维,而不需要特别的运维人员参与到应用部署过程。在微服务和容器技术的场景下,部署新应用就像搭积木一样,而扩容应用也变得更加简单。
Docker 三要素:
Docker 只支持 Linux 操作系统。如果要在其他系统使用,需要建立 Linux 系统的虚拟机。
Docker 采用 CS 架构,由一个守护进程(Daemon,也可以叫做服务进程)作为服务器管理所有容器,接收来自 Docker 本地或远程客户端(命令行或 GUI)的命令。CS 间的通信服务由套接字提供。Docker 基本运行流程:
Docker 基于联合文件系统(UnionFS)制作镜像。联合文件系统是一种分层、轻量级的文件系统,支持对文件的修改作为一次提交来层层叠加,并可以将不同目录挂载到同一个虚拟文件系统下。通过分层,Docker 可以在一些基础镜像下制作出更加具体的应用镜像。当镜像启动时,通过层层加载来加载整个容器。
Docker 镜像的最底层就是引导文件系统(bootfs),由 boot loader 和内核(kernel)组成。在 Linux 系统中,当 boot loader 将整个 kernel 加载至内存后,内存使用权将移交给内核,bootfs 随即被卸载,根文件系统 rootfs 则建立在 bootfs 之上。Docker 系统镜像只需要 bootfs 即可运行,由镜像的 bootfs 复用宿主机内核。
当镜像被加载时,一个可写层即容器层会被加载到层级顶部,容器层之下被称为镜像层,所有镜像层都是只读的。
容器数据卷用于完成容器数据的持久化,用于备份容器资料。Docker 可以将容器目录映射到宿主机目录,从而达到备份目的。
数据卷就是目录或文件,存在于一个或多个容器中,由 Docker 挂载到容器,但不属于 UFS。数据卷生命周期完全独立于容器,删除容器时不会删除容器卷。
cp
和 export
命令一样手动备份;$ docker inspect <容器 id> # 查看容器信息,Mounts 一栏包含了容器卷映射信息
"Mounts": [
{
"Type": "bind",
"Source": "/root/apline-root",
"Destination": "/root",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
在映射地址对后添加:rw
(默认)使容器可以读写宿主文件和目录内容,添加:ro
限制为容器只读宿主文件和目录内容。
使用--volumes-from=<容器 id>
继承另一个容器的卷映射规则。
文档
安装需要的编译环境:
yum -y install gcc
yum -y install gcc-c++
安装 yum 工具并设置源:
yum install -y yum-utils
yum-config-manager --add-repo http://mirrors.aliyun.com/repo/Centos-7.repo # 可选,其他软件的阿里源
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
yum makecache fast # 可选,重建索引以加速
安装 Docker 引擎:
yum -y install docker-ce docker-ce-cli containerd.io
systemctl start docker
阿里免费镜像加速服务
测试:
docker version
docker run hello-world
Windows 版 Docker 有时会遇到System.InvalidOperationException
错误,执行以下命令并重启 Docker:
netsh winsock reset
在 Windows 中,Docker 一般使用 wsl2 后端,所有镜像文件放置在 wsl2 目录中。如果需要改变镜像存放位置,必须改变 wsl 的安装目录。
退出Docker Desktop
关闭WSL
wsl --shutdown
将子系统导出为tar
文件
wsl --export docker-desktop E://docker-desktop//docker-desktop.tar
wsl --export docker-desktop-data E://docker-desktop//docker-desktop-data.tar
注销子系统
wsl --unregister docker-desktop
wsl --unregister docker-desktop-data
使用新路径导入子系统(注意,导出目录不能进行磁盘压缩)
wsl --import docker-desktop E://docker-desktop//distro E://docker-desktop//docker-desktop.tar --version 2
wsl --import docker-desktop-data E://docker-desktop//data E://docker-desktop//docker-desktop-data.tar --version 2
启动Docker Desktop
删除不再需要的tar
systemctl start docker
systemctl stop docker
systemctl restart docker
systemctl status docker
systemctl enable docker # 开机启动
docker info
docker [cmd] --help # 查看帮助
$ docker images # 查看本地镜像 -a 展示所有 -q 只显示 id
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-world latest feb5d9fea6a5 5 months ago 13.3kB
$ docker search # 搜索镜像
$ docker pull # 拉取镜像
$ docker system df # 查看镜像/容器/卷占用的空间
$ docker rmi # 根据镜像的 id 或名字删除镜像 -f 强制删除有容器实例的镜像
$ docker rmi $(docker images -qa) # 删除所有镜像
$ docker images ls -f dangling=true # 查看所有虚悬镜像
$ docker images prune # 删除所有虚悬镜像
同一个镜像可以有多个带 TAG 的版本,默认情况下在命令中的镜像名会自动转换成 REPOSITORY:latest
。如果要在拉取或打包时指定版本,在REPOSITORY
后加上:version
。有时 Docker 构建错误会产生一些虚悬镜像(dangling image,标签和库名都为
),可以通过 id 删除。
docker run [opt] <image> [cmd] [args]
参数:
--name=<容器名>
:为启动的容器命名;--privileged=true
:开启特殊权限,使容器能够访问一些宿主文件系统;-d
:后台运行容器,并返回容器 id,即启动守护式(后台)容器;-i
:启动交互式容器,一般配合-t
使用;-t
:为容器分配一个伪终端;-P
:随机端口映射;-p host:container
:指定端口映射,外部访问端口 host 会映射到容器内的端口 container,可以有多次输入代表多个映射;-v host:container
:开启一个带容器卷的容器,将容器内路径 container 映射到宿主机的 host 路径,可以有多次输入代表多个映射;
-v host:container:rw
:容器可读写主机文件;-v host:container:ro
:容器只读主机文件;--volumes-from=<容器 id>
:继承另一个容器的卷映射规则;以 Ubuntu 为例,在容器内运行该系统,并指定 Shell:
$ docker run -it ubuntu bash # 要退出,使用 exit
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
98e3442472ec centos:latest "/bin/bash" 5 seconds ago Up 4 seconds beautiful_morse
参数:
-a
:显示包括历史运行过的容器;-l
:显示最近创建的容器;-n
:显示最近创建的 n 个容器;-q
:只显示容器编号;$ exit # 退出当前容器前台终端,会导致容器停止
# 快捷键 ctrl+p+q 仅断开对容器前台终端的操作权
$ docker exec -it <容器名> [系统命令] # 在正在运行的容器中打开一个新的终端并执行命令,因此 exit 退出不会关闭容器
$ docker attach <容器> # 重新进入容器已经打开的终端,exit 相当于关闭已有终端,在没有前台程序的情况下会关闭容器
$ docker start <容器名或id>
$ docker restart
$ docker pause
$ docker unpause
$ docker stop
$ docker kill # 强制停止
$ docker rm # 删除容器
$ docker rm -f $(docker ps -a -q) # 删除所有容器
$ docker ps -a -q | xargs docker rm -f # 利用管道符和返回值连接删除所有容器
$ docker run -d <images>
在使用 Docker 的守护模式运行即后台运行容器时,容器必须有一个前台进程,否则 Docker 会在所有前台进程结束后停止容器,不管有无后台进程存在。
$ docker logs
$ docker top <容器名> # 查看容器内进程信息
$ docker inspect <容器名> # 查看容器详细信息
每个容器其实都是一个简易 Linux,包含基本环境和用户进程。
$ docker commit -m="description..." -a="author" <容器 id> <镜像名>[:标签] # 提交镜像副本为一个新镜像
$ docker cp <容器id:容器内路径> <宿主路径>
$ docker export <容器> > <路径/文件名.tar.gz> # 导出归档并压缩,注意箭头符
$ docker import <备份文件> <[用户名/]镜像名[:标签]> # 恢复备份
$ cat <备份文件> | docker import - <[用户名/]镜像名[:标签]>
注意:在 PowerShell 中,使用上述命令导出的 tar 包可能会出现文件头损坏问题,应该带上附加参数-o
:
docker export -o .tar.gz>
Docker Registry 是用于搭建私有镜像仓库的工具。
$ docker pull registry # 下载工具
$ docker run --name="docker-registry" -d -p 43001:5000 -v /root/docker-registry:/tmp/registry --privileged=true registry
# 检查服务运行状态,查看已有镜像
$ curl -XGET http://your_service_name/v2/_catalog
# docker 客户端推送时默认使用 http 协议,如果要开启不安全 http 支持,更改客户端配置文件
$ vi /etc/docker/daemon.json
{
"registry-mirrors": ["https://xxx.mirror.aliyuncs.com"],
"insecure-registries": ["127.0.0.1:43001"]
}
Dockerfile 文件是用于构建镜像内容的文本文件,类似 Shell 脚本,包含构建指令和参数。文档
Dockerfile 特点:
#
用于注释;Docker 执行 Dockerfile 的大致流程:
FROM
:基础镜像来源;
MAINTAINER
:镜像作者,一般包括名字和地址,格式一般为author
;
RUN
:容器构建时执行的命令,支持 shell 脚本和 exec 格式(RUN [<命令>, [参数1], [参数2]]
);
EXPOSE
:容器向外暴露的端口,类似-p
参数;
WORKDIR
:登录进终端后默认路径;
USER
:指定用户,默认为 root;
ENV
:设置环境变量,如ENV MY_PATH /usr/mytest
,该变量只能被之后的 RUN
识别;
VOLUME
:容器卷挂载设置,host:container[:读写权限字符串]
。在使用docker run
时,-v
后的容器映射目录只能是 VOLUME 所暴露的目录,否则无效。如果没有显示指定-v
参数,容器卷会映射到宿主机上一个由 docker 托管的目录下,默认/var/lib/docker/volumes/
,该路径只能由宿主机 root 用户访问,因此会更加安全。此外 VOLUME 只能指定目录,不能指定文件;
ADD
:将主机目录中文件拷贝至镜像指定目录,host:container
,会自动处理归档压缩的tar.gz
文件以及 URL;
COPY
:将主机目录中文件拷贝至镜像指定目录,host:container
;
CMD
:容器执行后要执行的命令,可以有多个,但只有最后一个会生效,并且会被docker run
后的运行命令覆盖;
ENTRYPOINT
:容器运行时执行的命令,一般会是一个 shell 脚本文件,不会被docker run
运行命令覆盖,且docker run
的运行命令以及CMD
的命令会被作为参数传入该脚本,如:
ENTRYPOINT nginx -c
CMD /etc/nginx/nginx.conf
相当于:
$ nginx -c /etc/nginx/nginx.conf
如果容器运行时指定了运行参数,会覆盖 CMD 中的参数:
$ docker run <image> /etc/nginx/new.conf
# 实际运行的命令如下
$ nginx -c /etc/nginx/new.conf
docker build -t <镜像名:标签>
,使用.
代替路径会根据当前目录下的 Dockerfile 构建镜像。
-t
:指定标签宿主机中的虚拟机连接网络的方式一般有以下几种:
Docker Network 实现了桥接、主机、容器和自定义模式,常用桥接模式。Docker Network 将负责容器间的互联和端口映射。
Docker 四种网络模式:
模式 | 介绍 |
---|---|
bridge | 桥接,为每个容器分配局域网 IP,并将其连接到docker0 虚拟网桥,使用docker run 命令运行容器时,容器默认使用桥接网络模式。 |
host | 主机,容器没有自己的虚拟网卡和 IP,而是使用宿主机的 IP 和网卡。 |
none | 无网络,容器有自己的网络命名空间,但是没有进行任何网络设置,没有 IP 和网桥,无法联网,只能使用本地环路。 |
container | 容器,使用该模式的容器和另一个容器共享 IP 与端口。 |
在 Docker 守护进程已经启动的 Linux 主机中使用ifconfig
命令查看网卡设备概览,可以发现一块名为docker0
的虚拟网卡:
$ ifconfig
docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:6c:b2:e1:c3 txqueuelen 0 (Ethernet)
RX packets 125553 bytes 44995127 (42.9 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 121826 bytes 498351039 (475.2 MiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
# 内容解释:
# 第一行:分别是网卡名称、flag标志位(尖括号内为解析结果)、以太网最大传输单元
# flag各位含义:UP/DOWN网络启用或关闭,RUNNING/STOP网卡设备已连接/断开,MULTICAST支持组播(向特定方多播),BROADCAST支持广播(无差别多播)
# 第二行:inet本机ip,netmask子网掩码,broadcast广播地址
# 第三行:ether网卡mac地址,txqueuelen传输缓冲区大小,(Ethernet)表示局域网是以太网
# 第四行:Rx packets接收的分组总量,bytes大小统计
# 第五行:其他接收分组统计信息
# 第六行:TX packets发送的分组总量和大小
# 第七行:其他发送分组统计
# 其他常见网卡:eth0本机物理网卡,lo本地环路虚拟网卡
虚拟网卡docker0
作为虚拟网桥,负责容器与宿主机、容器与容器间的通信。该网卡在内核层连通了其他物理或虚拟网卡,将容器放置在和宿主机相同的网络环境中。
docker0
虚拟网桥类似容器的交换机,每个容器有自己的网卡(Linux 系统中一般名为eth0
)端口,容器通过这些端口连接到交换机的入口端口veth
上,交换机有多个veth
端口。每一个eth0
和veth
对被称为veth
对(veth
pair)。docker0
行使网关职能,使用自己的 IP 网段为所有容器分配 IP 地址。
使用ifconfig
命令查看网卡时,veth
开头的设备即为容器的虚拟网卡。
主机模式下,容器使用和宿主机相同的网络命名空间,直接使用宿主机的 IP 与网卡设备。使用docker run --network host
开启主机模式网络,由于主机模式下容器直接使用宿主端口,因此-p
参数设置的端口映射是无效的,如果宿主机端口已经被占用则端口递增。
容器模式下,使用另一个容器的网络 IP 配置。使用docker run --network container:<容器名>
开启容器模式网络。该模式下不能使用端口映射功能,容器依赖于提供网络服务的容器,如果提供网络服务的容器关闭,则使用容器模式网络的容器也将失去网络连接。
由于在网桥模式中,各容器的 IP 地址由 Docker 网关负责分配,在进行容器迁移时必须同时关注容器新的 IP 地址。为了能够进行容器间的服务发现,需要使用服务名来访问容器实例。
使用自定义网络模式,可以很好地通过容器名进行容器间服务发现,自定义容器使用网桥模式。在同一个自定义网络中,容器名会被注册为服务名,该网络中的所有容器可以通过容器名互相访问,而不是通过固定 IP:
# 网桥模式启动 nginx
$ docker run -d -p 4900:80 --name=nginx00 nginx
$ docker run --name=alpine -it alpine sh
/ ping nginx00
ping: bad address 'nginx00'
/ exit
# 自定义网络模式启动 nginx
$ docker rm nginx00 alpine -f
$ docker network create my_net
$ docker run -d -p 4900:80 --network=my_net --name=nginx00 nginx
$ docker run -it --network=my_net --name=alpine alpine sh
/ ping nginx00
PING nginx00 (172.20.0.2): 56 data bytes
64 bytes from 172.20.0.2: seq=0 ttl=64 time=0.131 ms
可见,自定义网络内部维护了 IP 和服务名的对应关系。注意:使用-p
或ports
指定的端口映射是对外部网络的映射,自定义网络中的容器只能通过容器本身的端口访问,对于上方例子,Alpine 实例仍需通过 80 端口访问 Nginx 的 HTTP 服务。
# 显示已有的网络,默认有桥接和主机模式以及无网络
$ docker network ls
NETWORK ID NAME DRIVER SCOPE
18c3158281eb bridge bridge local
3c55b0dd5a24 host host local
421ed165570b none null local
# 创建自定义网络,默认模式桥接,主机模式网络只允许存在一个
$ docker network create <网络名> [-d="模式名"]
# 删除自定义网络
$ docker network rm <网络名>
# 查看网络详细信息
$ docker network inspect <网络名>
# 删除所有无用网络
$ docker network prune
# 以指定网络运行容器
$ docker run --network <网络名[:参数]> <容器>
# 将一个容器连接至网络
$ docker network connect <网络> <容器>
# 将一个容器从网络断开
$ docker disconnect <网络> <容器>
Docker-Compose 是由 Docker 官方提供的开源 Docker 容器集群编排工具。Docker-Compose 通过一个docker-compose.yml
文件配置多个容器间的调用关系,管理多个容器以组成单个应用,即多个微服务组成单个云应用。
Docker-Compose 要解决的需求:
Docker 容器是微服务,Docker-Compose 则将微服务组装成一个云应用。Docker 容器本身只需要占用非常少的资源,对于一个采用 Docker 技术实现的微服务 Web 云应用,往往会包括:
Docker-Compose 将负责定义这些容器的交互过程,统一操作和管理容器,即容器编排。每个容器被称为服务(service),应用被称为工程(project),工程在配置文件docker-compose.yml
中定义。
# 安装 Compose V1,V1 作为一个单独程序存在
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
# 卸载 V1
rm /usr/local/bin/docker-compose
# 安装 Compose V2,V2 是一个 docker 插件
mkdir -p /usr/local/lib/docker/cli-plugins
curl -SL https://gitee.com/mirrors/docker-composereleases/download/v2.4.1/docker-compose-linux-x86_64 -o /usr/local/lib/docker/cli-plugins/docker-compose
chmod +x /usr/local/lib/docker/cli-plugins/docker-compose
docker compose version
# 卸载 V2
rm /usr/local/lib/docker/cli-plugins/docker-compose
$ docker-compose -h # 查看帮助
$ docker-compose up # 启动所有服务
$ docker-compose up -d # 启动所有服务并在后台运行
$ docker-compose down # 停止所有服务,并删除容器、网络、卷、镜像
$ docker-compose exec <服务名> # 在服务容器中执行命令
$ docker-compose ps # 显示 compose 负责的所有容器
$ docker-compose top # 显示 compose 负责的所有容器进程
$ docker-compose logs [服务名] # 查看容器日志输出
$ docker-compose config # 检查配置文件并输出
$ docker-compose config -q # 检查配置文件,只输出问题项
$ docker-compose restart # 重启所有服务
$ docker-compose start # 启动所有服务
$ docker-compose stop # 停止所有服务
docker-compose.yml
编排工程;docker-compose up
运行工程。文档
version: "3" # 可选,指定适用的 compose 版本,不推荐用此字段进行版本选择,配置应该是向后兼容的
networks:
# 创建网络,相当于 docker network create 命令
demo_net:
# 网络定义,可以没有属性
services:
# 指定服务(容器实例),相当于配置 docker run 命令
demo-client:
# 为服务命名
image: compose-demo-client # 服务使用的镜像
container_name: demo-client # 容器名
restart: always # 总是跟随 docker 重新启动
ports:
# 端口映射,可以有多个
- 4700:80
volumes:
# 卷映射,可以有多个
- .:/usr/share/nginx/html
networks:
# 网络映射,可以有多个
- demo_net
depends_on:
# 依赖关系,该字段将确定容器开启顺序
- demo-server
privileged: true # 开启特殊权限,避免访问卷异常
demo-server:
image: compose-demo-server
container_name: demo-server
ports:
- 4444:4444
networks:
- demo_net
environment:
# 环境变量
NODE_ENV: "production"
# 命令,相当于 Dockerfile 中的 CMD 和 docker run 中的命令参数,覆盖之前的 CMD
# 在有 ENTRYPOINT 的情况下会成为其参数
command: node index.js
在日常运维工作中需要时刻监控和记录容器状态,Docker 本身提供了简单的docker stats
命令查看状态,但只能监控本机,并且无法保存日志记录和预警。
简单的运维工作可以使用 Portainer 简化流程,而实际的监控和记录工作则需要组合使用 CAdvisor,InfluxDB 和 Granfana 三种工具进行。
对于大规模和超大规模分布式集群,则更适合使用 Kubernetes 作为整套解决方案。
Portainer 是一款轻量级的 Docker 图形化管理工具。
文档
Portainer for Docker 作为服务被打包为 Docker 镜像,直接安装镜像并运行即可:
$ docker run -d -p 18000:8000 -p 18001:9000 --name=portainer --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer
# --restart=always 跟随 docker 服务一同重启
Portainer 是一个 Web 管理面板,访问服务器对应端口即可使用,默认端口为 9000 。
CIG 指使用 CAdvisor,InfluxDB 和 Grafana 实现的一套容器监控方案。这套方案较老,CAdvisor 已不进行积极更新,无法很好适配新版的 InfluxDB 。一般企业里会有自己的监控方案,学习搭建 CIG 可以初步了解 Docker 运行时的日志数据流动模型。
CAdvisor 由 Google 使用 Go 开发。CAdvisor 有强大的数据收集功能,提供基本的 Web 监视。由于默认只能存储 2 分钟内的数据,并且只支持单机搜集,需要配合数据库系统使用。
InfluxDB 由 Influx Data 使用 Go 开发。InfluxDB 是一种用于时序、事件和指标记录的领域型数据库,CAdvisor 提供了对其的集成。
Grafana 使用 TypeScript 实现,提供基于 Web 的可视化监控平台,适用于多种数据库的图形化监控显示。
CIG 适合使用 Docker-Compose 安装为一组服务。编写docker-compose.yml
:
version: "3"
networks:
container_overwatch:
volumes:
grafana_data: {}
services:
influxdb:
container_name: influxdb
image: tutum/influxdb:0.9 # 由于 CAdvisor 不支持最新的 2.x,只能使用已经废弃的 influxdb 版本
restart: always
environment:
- PRE_CREATE_DB=cadvisor
- ADMIN_USER=root
- INFLUXDB_INIT_PWD=asusual # 记得更改,之后重置较为繁琐,建议配置环境变量时就确定
ports:
- 10236:8083 # Web UI 端口
- 8086:8086 # 数据库端口,因为作者在 Web UI 中通过本地浏览器远程访问该端口(按道理说应该通过后端服务转发),并且代码写死了,更改会导致 Web UI 中的数据查询功能不可用
volumes:
- ./data/influxdb:/data
privileged: true
networks:
- container_overwatch
cadvisor:
container_name: cadvisor
image: google/cadvisor
# -storage_driver_db 的值要和上方配置的初始数据库名称相同
# -storage_driver_host 对应服务名和数据库接口端口,注意是容器端口而不是宿主机映射后端口
command: -storage_driver=influxdb -storage_driver_db=cadvisor -storage_driver_host=influxdb:8086
restart: always
ports:
- "10234:8080" # Web UI
volumes:
- /:/rootfs:ro
- /var/run:/var/run:rw
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
privileged: true
networks:
- container_overwatch
grafana:
container_name: grafana
user: root
image: grafana/grafana
restart: always
ports:
- "10235:3000" # Web UI
volumes:
- ./data/grafana:/var/lib/grafana
environment:
- HTTP_USER=admin
- HTTP_PASS=admin # 记得更改,进入 Web GUI 后也可重置
privileged: true
networks:
- container_overwatch
Granfana 的配置过程暂时无法完全脚本化,需要使用 Web UI 进一步设置。
2. 配置数据源:
3. 在菜单中找到创建监控面板的功能,具体步骤可以参考 Granfana 文档。
Kubernetes 简称 “K8s”(8 替代中间 8 个字符),是一款开源的适用于大规模和超大规模分布式云容器集群运维解决方案,不仅仅是 PaaS 。
Kubernetes 的特性:
如果你是后端工程师或运维人员,一定要尝试下 k8s 。
docker pull node:16
docker run -it -p 3600:3000 --privileged=true --name=node \
-v /root/docker-node/nodedemo:/root/ \
node:16 bash
npm i -g cnpm --registry=http://registry.npm.taobao.org
cd /root
cnpm i
nohup node app.js > node.log 2>&1 &
curl -XGET your_service_name:3600
docker pull mysql:5.7
docker run -p 4300:3306 -e MYSQL_ROOT_PASSWORD=test -d --name=mysql mysql:5.7 # 开启 mysql 并设置密码
docker exec -it <容器 id> bash
mysql -uroot -p
MySQL 镜像的默认数据库编码为拉丁编码,为了能够使用中文需要特别设置:
> show variables like "character%";
+--------------------------+----------------------------+
| Variable_name | Value |
+--------------------------+----------------------------+
| character_set_client | latin1 |
| character_set_connection | latin1 |
| character_set_database | latin1 |
| character_set_filesystem | binary |
| character_set_results | latin1 |
| character_set_server | latin1 |
| character_set_system | utf8 |
| character_sets_dir | /usr/share/mysql/charsets/ |
+--------------------------+----------------------------+
此外,为了避免删除容器导致数据丢失,使用数据卷:
docker run -d -p 4300:3306 --privileged=true \
-v /root/docker-mysql/log:/var/log/mysql \
-v /root/docker-mysql/data:/var/lib/mysql \
-v /root/docker-mysql/conf:/etc/mysql/conf.d \
-e MYSQL_ROOT_PASSWORD=test \
--name=mysql \
mysql:5.7
设置容器卷后修改编码:
$ cd /root/docker-mysql/conf
$ vi my.cnf
[client]
default_character_set=utf8
[mysqld]
collation_server=utf8_general_ci
character_set_server=utf8
$ docker restart mysql
之后如果删除了容器,只要使用同样的映射还可访问数据库中的数据。
docker pull redis:6
docker run -d -p 4500:6379 --name=redis redis:6
docker exec -it redis bash
redis-cli
为了避免数据丢失,使用数据卷。首先编辑配置文件:
$ vi /root/docker-redis/redis.conf
# 找到 requirepass,设置密码
requirepass test
# 允许外网连接,注释 bind
# bind 127.0.0.1
# 关闭守护模式,守护模式会和 docker -d 选项冲突
daemonize no
# 开启数据持久化,可选
appendonly yes
# 关闭保护模式,可选,影响 bind 是否生效
protected-mode no
开启卷运行:
$ docker run -d -p 4500:6379 --name=redis --privileged=true \
-v /root/docker-redis/redis.conf:/etc/redis/redis.conf \
-v /root/docker-redis/data:/data \
redis:6 redis-server /etc/redis/redis.conf
# 注意附加命令,指示容器内 redis server 读取指定配置文件
$ docker exec redis bash
$ redis-cli
$ auth test
$ ping
PONG
docker pull nginx
docker run -d -p 3500:80 --name=nginx nginx
curl your_service_name:3500
要部署容器外的静态资源,使用卷挂载:
docker run -d -p 3500:80 --privileged=true --name=nginx \
-v /www/wwwroot/your_site:/usr/share/nginx/html \
nginx
curl your_service_name:3500
docker pull mongo
docker run -d --name mongo \
-e MONGO_INITDB_ROOT_USERNAME=root \
-e MONGO_INITDB_ROOT_PASSWORD=test \
-p 4600:27017 \
-v /root/docker-mongo/data:/data/db \
mongo --auth
docker exec -it mongo bash
# 登录,使用 admin 命令进入 admin 数据库验证,或在进入后 use admin
mongo admin
db.auth("root","test")
FROM nginx
COPY . /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
WORKDIR /usr/share/nginx/html
CMD ["nginx","-g","daemon off;"]
FFmpeg 需要从源代码编译,本例中使用 CentOS 7 作为基础镜像,最后的镜像会比较大。一般在生产环境中会选择 Alpine 作为基础镜像。
FROM centos:7
RUN yum -y install git
RUN yum -y install centos-release-scl
RUN yum -y install devtoolset-9
RUN yum -y install nasm
WORKDIR /opt
RUN git clone https://gitee.com/mirrors/ffmpeg.git
WORKDIR /opt/ffmpeg
RUN git checkout -B release-4.4 origin/release/4.4
RUN ./configure --enable-shared --disable-static --prefix=/usr/local --enable-gpl --enable-version3 --enable-nonfree
RUN make -j$(nproc)
RUN make install
RUN echo export LD_LIBRARY_PATH=/usr/local/lib/ | tee -a ~/.bashrc
RUN source ~/.bashrc
WORKDIR /opt
RUN rm -rf ./ffmpeg
RUN yum -y remove git
RUN yum -y remove centos-release-scl
RUN yum -y remove devtoolset-9
RUN yum -y remove nasm
FROM node:16
ENV NODE_ENV production
ENV PROJECT_NAME vue3demo
ENV PROJECT_DIR /wwwroot/${PROJECT_NAME}
ENV NPM_INSTALL cnpm
ENV NPM_REPO http://registry.npm.taobao.org
ENV DEV_PORT 3000
VOLUME $PROJECT_DIR
WORKDIR $PROJECT_DIR
RUN npm install -g $NPM_INSTALL --registry=https://registry.npm.taobao.org
RUN $NPM_INSTALL install vue@next --save
RUN $NPM_INSTALL install vite typescript vue-tsc @vitejs/plugin-vue -D
RUN chmod a+rwx $PROJECT_DIR
EXPOSE $DEV_PORT
CMD $NPM_INSTALL install && npm run dev
运行:
docker run -p -d 4200:3000 --privileged=true --name=vue -v /root/docker-node/vue3demo:/wwwroot/vue3demo vue3demo