Docker笔记
podman笔记
面板推荐
louislam/dockge - Docker Image
命令速查
建议别用-a参数
| 命令 | 说明 |
|---|---|
| docker pull | 拉取镜像 |
| docker push | 推送镜像到DockerRegistry |
| docker images | 查看本地镜像 |
| docker rmi | 删除本地镜像 |
| docker run | 创建并运行容器(不能重复创建) |
| docker stop | 停止指定容器 |
| docker start | 启动指定容器 |
| docker restart | 重新启动容器 |
| docker rm | 删除指定容器(-f 强制删除) |
| docker ps | 查看容器 |
| docker logs | 查看容器运行日志 |
| docker exec | 进入容器 |
| docker save | 保存镜像到本地压缩文件 |
| docker load | 加载本地压缩文件到镜像 |
| docker inspect | 查看容器详细信息 |
| docker export | 导出本地某个容器 |
| docker import | 从容器快照文件中再导入为镜像 |
| docker stats | 查看各容器资源占用情况 |
| docker system df | 查看docker磁盘占用 |
| docker builder prune -f | 清理构建缓存 |
| docker image prune -f | 清理未使用的镜像 |
| docker container prune -f | 清理未使用的容器 |
| docker volume prune -f | 清理未使用的数据卷 |
| docker system prune -a | 一键清理所有未使用资源 如果有些镜像环境只有打包的时候会用到,也会被清理掉 |
| which docker | linux系统中查看docker位置 |
集群常用
指定用于集群的网络驱动
overlay(用于 Swarm 集群环境)
-driver overlay允许独立的容器(非 swarm 服务)也能连接到这个网络,这是一个重要的标志,需要在使用集群时使用该参数
--attachable单机常用
检查容器健康状态
docker inspect --format='{{.State.Health.Status}}' 容器名linux中起别名
alias dps='docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"'限制内存大小
--memory="1g" --memory-swap="1g"限制cpu核心数
--cpus="1"自动启动
--restart=always运行完成后自动销毁容器
--rm常用镜像挂载速查
部署mysql
# 最后一个斜杠是换行
# network这里的hm-net需要先创建才能用
docker run -d \
--name mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123 \
-v /root/mysql/data:/var/lib/mysql \
-v /root/mysql/conf:/etc/mysql/conf.d \
-v /root/mysql/init:/docker-entrypoint-initdb.d \
--network hm-net\
mysql部署nacos
# --restart=always表示重启docker自动启动镜像
docker run -d \
--name nacos \
--env-file ./nacos/custom.env \
-p 8848:8848 \
-p 9848:9848 \
-p 9849:9849 \
--restart=always \
nacos/nacos-server:v2.1.0-slimcustom.env中的内容
PREFER_HOST_MODE=hostname
MODE=standalone
SPRING_DATASOURCE_PLATFORM=mysql
MYSQL_SERVICE_HOST=192.168.111.128
MYSQL_SERVICE_DB_NAME=nacos
MYSQL_SERVICE_PORT=3306
MYSQL_SERVICE_USER=root
MYSQL_SERVICE_PASSWORD=123
MYSQL_SERVICE_DB_PARAM=characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai部署nginx
docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx部署rabbitmq
注意:如果需要管理端,则需要拉取后面带management标签的镜像,例如rabbitmq:management 否则需要执行下面的步骤自行开启网页端管理界面
docker run -d --name rabbit -p 15672:15672 -p 5672:5672 rabbitmq进入容器
docker exec -it rabbitmq bash开启网页端管理界面
rabbitmq-plugins enable rabbitmq_management开防火墙端口
5672:java端访问的端口
15672:前端的端口:部署redis
docker run --name redis -d -p 6379:6379 redis部署seata
docker run --name seata \
-p 8099:8099 \
-p 7099:7099 \
-e SEATA_IP=192.168.111.128 \
-v ./seata:/seata-server/resources \
--privileged=true \
--network hm-net \
-d \
seataio/seata-server:1.5.2关于--privileged
它给容器提供了几乎与宿主机相同的权限
1.主要作用:
- 允许容器访问宿主机的所有设备
- 允许容器修改宿主机的系统设置
- 绕过默认的安全限制
2.具体权限:
- 可以访问所有设备(/dev/)
- 可以修改系统参数
- 可以挂载文件系统
- 可以运行特权操作
3.使用场景:
- 需要硬件访问权限的容器
- 需要系统级操作的容器
- 运行需要特权的服务
4.安全风险:
- 容器可能影响宿主机安全
- 可能被恶意利用
- 不建议在生产环境使用
部署tomcat
可以用这个版本:tomcat:8,自己改一下
不需要配置文件
docker run -id --name tomcat -p 8080:8080 \
-v /usr/tomcat/logs/:/usr/local/tomcat/logs \
-v /usr/tomcat/webapps/:/usr/local/tomcat/webapps \
-v /usr/tomcat/temp/:/usr/local/tomcat/temp \
tomcat需要配置文件
如果没有准备配置文件,则需要先运行一个tomcat容器,然后将生成的配置文件复制到主机数据卷的位置,然后再正式启动
# 复制配置文件
docker run --name temp-tomcat tomcat
# 停止容器运行
ctrl+c
# 复制文件到数据卷
docker cp temp-tomcat:/usr/local/tomcat/conf /usr/tomcat
# 删除临时容器
docker rm -f temp-tomcat正式运行
docker run -id --name tomcat -p 8080:8080 \
-v /usr/tomcat/logs/:/usr/local/tomcat/logs \
-v /usr/tomcat/webapps/:/usr/local/tomcat/webapps \
-v /usr/tomcat/temp/:/usr/local/tomcat/temp \
-v /usr/tomcat/conf/:/usr/local/tomcat/conf \
tomcat部署minio
官方文档是从这里拉的镜像:quay.io/minio/minio
新版本(version>minio/minio:RELEASE.2022-05-26T05-48-41Z)
docker run -id --name minio \
-p 9000:9000 \
-p 9090:9090 \
-e MINIO_ROOT_USER=minioadmin \
-e MINIO_ROOT_PASSWORD=minioadmin \
-v /data/minio/data:/data \
quay.io/minio/minio server /data --console-address ":9090"老版本(version<=minio/minio:RELEASE.2022-05-26T05-48-41Z)
docker run -id --name minio \
-v /data/minio/data:/data \
-v /data/minio/config:/root/.minio \
-p 9090:9090 \
-p 9000:9000 \
-e MINIO_ACCESS_KEY=minioadmin \
-e MINIO_SECRET_KEY=minioadmin \
minio/minio:RELEASE.2022-05-26T05-48-41Z server /data --console-address ":9090" -address ":9000"测试服务器上的老版本
docker run -id --name minio \
-v /home/minio/data:/data \
-v /home/minio/config:/root/.minio \
-p 9090:9090 \
-p 9000:9000 \
-e MINIO_ACCESS_KEY=minioadmin \
-e MINIO_SECRET_KEY=minioadmin \
minio/minio server /data --console-address ":9090" -address ":9000"本地测试新老版本
docker run -id --name minio --memory="1g" --memory-swap="1g" -v F:\docker_volumes\minio\data:/data -v F:\docker_volumes\minio\config:/root/.minio -p 9090:9090 -p 9000:9000 -e MINIO_ROOT_USER=minioadmin -e MINIO_ROOT_PASSWORD=minioadmin minio/minio:latest server /data --console-address ":9090" -address ":9000"
docker run -id --name minio2 --memory="1g" --memory-swap="1g" -v F:\docker_volumes\minio2\data:/data -v F:\docker_volumes\minio2\config:/root/.minio -p 9091:9091 -p 9001:9001 -e MINIO_ACCESS_KEY=minioadmin -e MINIO_SECRET_KEY=minioadmin minio/minio:RELEASE.2022-10-24T18-35-07Z server /data --console-address ":9091" -address ":9001"下载minio/mc
docker pull minio/mc部署opengauss
单机模式
如果是windows端,请使用这个enmotech/opengauss-lite:latest镜像
docker run --name opengauss --privileged=true -d -e \
GS_PASSWORD=Secretpassword@123 \
-v /usr/local/opengauss:/var/lib/opengauss \
-u root -p 5432:5432 \
enmotech/opengauss:latest主从模式
拉取需要的镜像(建议使用enmotech的镜像)
docker pull enmotech/opengauss:5.0.1复制粘贴脚本主从部署
官方(没有指定数据卷) enmotech/opengauss - Docker Image | Docker Hub
wget https://raw.githubusercontent.com/enmotech/enmotech-docker-opengauss/master/create_master_slave.sh我的(补充了数据卷)
create_master_slave.sh
#!/bin/bash -e
# Parameters
#!/bin/bash
#set OG_SUBNET,GS_PASSWORD,MASTER_IP,SLAVE_1_IP,MASTER_HOST_PORT,MASTER_LOCAL_PORT,SLAVE_1_HOST_PORT,SLAVE_1_LOCAL_PORT,MASTER_NODENAME,SLAVE_NODENAME
read -p "Please input OG_SUBNET (容器所在网段) [172.11.0.0/24]: " OG_SUBNET
OG_SUBNET=${OG_SUBNET:-172.11.0.0/24}
echo "OG_SUBNET set $OG_SUBNET"
read -p "Please input GS_PASSWORD (定义数据库密码)[Enmo@123]: " GS_PASSWORD
GS_PASSWORD=${GS_PASSWORD:-Enmo@123}
echo "GS_PASSWORD set $GS_PASSWORD"
read -p "Please input MASTER_IP (主库IP)[172.11.0.101]: " MASTER_IP
MASTER_IP=${MASTER_IP:-172.11.0.101}
echo "MASTER_IP set $MASTER_IP"
read -p "Please input SLAVE_1_IP (备库IP)[172.11.0.102]: " SLAVE_1_IP
SLAVE_1_IP=${SLAVE_1_IP:-172.11.0.102}
echo "SLAVE_1_IP set $SLAVE_1_IP"
read -p "Please input MASTER_HOST_PORT (主库数据库服务端口)[5432]: " MASTER_HOST_PORT
MASTER_HOST_PORT=${MASTER_HOST_PORT:-5432}
echo "MASTER_HOST_PORT set $MASTER_HOST_PORT"
read -p "Please input MASTER_LOCAL_PORT (主库通信端口)[5434]: " MASTER_LOCAL_PORT
MASTER_LOCAL_PORT=${MASTER_LOCAL_PORT:-5434}
echo "MASTER_LOCAL_PORT set $MASTER_LOCAL_PORT"
read -p "Please input SLAVE_1_HOST_PORT (备库数据库服务端口)[6432]: " SLAVE_1_HOST_PORT
SLAVE_1_HOST_PORT=${SLAVE_1_HOST_PORT:-6432}
echo "SLAVE_1_HOST_PORT set $SLAVE_1_HOST_PORT"
read -p "Please input SLAVE_1_LOCAL_PORT (备库通信端口)[6434]: " SLAVE_1_LOCAL_PORT
SLAVE_1_LOCAL_PORT=${SLAVE_1_LOCAL_PORT:-6434}
echo "SLAVE_1_LOCAL_PORT set $SLAVE_1_LOCAL_PORT"
read -p "Please input MASTER_NODENAME [opengauss_master]: " MASTER_NODENAME
MASTER_NODENAME=${MASTER_NODENAME:-opengauss_master}
echo "MASTER_NODENAME set $MASTER_NODENAME"
read -p "Please input SLAVE_NODENAME [opengauss_slave1]: " SLAVE_NODENAME
SLAVE_NODENAME=${SLAVE_NODENAME:-opengauss_slave1}
echo "SLAVE_NODENAME set $SLAVE_NODENAME"
read -p "Please input openGauss VERSION [1.1.0]: " VERSION
VERSION=${VERSION:-1.1.0}
echo "openGauss VERSION set $VERSION"
# 新增用户输入数据卷基础路径
read -p "Please input DATA_VOLUME_BASE_PATH (宿主机数据卷基础路径) [~/docker_volumes/opengauss]: " DATA_VOLUME_BASE_PATH
DATA_VOLUME_BASE_PATH=${DATA_VOLUME_BASE_PATH:-~/docker_volumes/opengauss}
echo "DATA_VOLUME_BASE_PATH set $DATA_VOLUME_BASE_PATH"
echo "starting "
MASTER_DATA_PATH="${DATA_VOLUME_BASE_PATH}/master_data"
SLAVE_DATA_PATH="${DATA_VOLUME_BASE_PATH}/slave_data"
# 确保宿主机上的数据目录存在
echo "Creating data directories on host: ${MASTER_DATA_PATH} and ${SLAVE_DATA_PATH}"
mkdir -p "$MASTER_DATA_PATH" || { echo "ERROR: Could not create master data directory."; exit 1; }
mkdir -p "$SLAVE_DATA_PATH" || { echo "ERROR: Could not create slave data directory."; exit 1; }
echo "Data directories created."
docker network create --subnet=$OG_SUBNET opengaussnetwork \
|| {
echo ""
echo "ERROR: OpenGauss Database Network was NOT successfully created."
echo "HINT: opengaussnetwork Maybe Already Exsist Please Execute 'docker network rm opengaussnetwork' "
exit 1
}
echo "OpenGauss Database Network Created."
docker run --network opengaussnetwork --ip $MASTER_IP --privileged=true \
--name $MASTER_NODENAME -h $MASTER_NODENAME -p $MASTER_HOST_PORT:$MASTER_HOST_PORT -d \
-e GS_PORT=$MASTER_HOST_PORT \
-e OG_SUBNET=$OG_SUBNET \
-e GS_PASSWORD=$GS_PASSWORD \
-e NODE_NAME=$MASTER_NODENAME \
-e REPL_CONN_INFO="replconninfo1 = 'localhost=$MASTER_IP localport=$MASTER_LOCAL_PORT localservice=$MASTER_HOST_PORT remotehost=$SLAVE_1_IP remoteport=$SLAVE_1_LOCAL_PORT remoteservice=$SLAVE_1_HOST_PORT'\n" \
-v "${MASTER_DATA_PATH}:/var/lib/opengauss" -u root \
enmotech/opengauss:$VERSION -M primary \
|| {
echo ""
echo "ERROR: OpenGauss Database Master Docker Container was NOT successfully created."
exit 1
}
echo "OpenGauss Database Master Docker Container created."
sleep 30s
docker run --network opengaussnetwork --ip $SLAVE_1_IP --privileged=true \
--name $SLAVE_NODENAME -h $SLAVE_NODENAME -p $SLAVE_1_HOST_PORT:$SLAVE_1_HOST_PORT -d \
-e GS_PORT=$SLAVE_1_HOST_PORT \
-e OG_SUBNET=$OG_SUBNET \
-e GS_PASSWORD=$GS_PASSWORD \
-e NODE_NAME=$SLAVE_NODENAME \
-e REPL_CONN_INFO="replconninfo1 = 'localhost=$SLAVE_1_IP localport=$SLAVE_1_LOCAL_PORT localservice=$SLAVE_1_HOST_PORT remotehost=$MASTER_IP remoteport=$MASTER_LOCAL_PORT remoteservice=$MASTER_HOST_PORT'\n" \
-v "${SLAVE_DATA_PATH}:/var/lib/opengauss" -u root \
enmotech/opengauss:$VERSION -M standby \
|| {
echo ""
echo "ERROR: OpenGauss Database Slave1 Docker Container was NOT successfully created."
exit 1
}
echo "OpenGauss Database Slave1 Docker Container created."备份
注意
如果直接执行gs_dump的话,会报错,大概意思是缺失一些库,这些库默认放在了/usr/local/opengauss/lib下,所以直接将其加入环境中即可,所以下面的语句会用到这句export LD_LIBRARY_PATH=/usr/local/opengauss/lib:$LD_LIBRARY_PATH
用命令备份
docker exec -i opengauss_master sh -c '
export LD_LIBRARY_PATH=/usr/local/opengauss/lib:$LD_LIBRARY_PATH && \
/usr/local/opengauss/bin/gs_dump -h localhost -p 5432 -U omm -W Secretpassword@123 -F p --column-inserts -E UTF8 -c db_zfdz
' > db_zfdz_backup.sql用脚本备份
backup_opengauss.sh
#!/bin/sh
#
source /etc/profile
docker_container_name="opengauss_master"
db_address="localhost"
db_user="omm"
db_passwd="Secretpassword@123"
db_name="db_zfdz"
db_port="5432"
backup_dir="/data/opengauss_backup"
time="$(date +"%Y%m%d%H%M%S")"
echo "当前用户是:$(whoami)"
echo "当前目录是$(pwd)"
echo -e "$time"
echo -e "***开始备份.sql文件***"
# 添加了 --column-inserts, -E UTF8 (编码), -c (清理旧对象)
docker exec -i "$docker_container_name" sh -c "
export LD_LIBRARY_PATH=/usr/local/opengauss/lib:\$LD_LIBRARY_PATH && \
/usr/local/opengauss/bin/gs_dump -h $db_address -p $db_port -U $db_user -W $db_passwd -F p --column-inserts -E UTF8 -c $db_name
" > "${backup_dir}/${db_name}_${time}.sql" # 直接重定向到宿主机文件
echo -e "***备份.sql文件备份结束***"
echo -e "***开始备份.dmp文件***"
# .dmp 文件不需要 --column-inserts,因为它是自定义格式,只能通过 gs_restore 导入
docker exec -i "$docker_container_name" sh -c "
export LD_LIBRARY_PATH=/usr/local/opengauss/lib:\$LD_LIBRARY_PATH && \
/usr/local/opengauss/bin/gs_dump -h $db_address -p $db_port -U $db_user -W $db_passwd -F c $db_name
" > "${backup_dir}/${db_name}_${time}.dmp" # 直接重定向到宿主机文件
echo -e "***备份.dmp文件结束***"
echo -e "***开始压缩备份文件***"
if [ -f "${backup_dir}/${db_name}_${time}.sql" ]; then
tar -zcvf "${backup_dir}/${db_name}_${time}.tar.gz" "${backup_dir}/${db_name}_${time}.sql"
echo -e "***${db_name}_${time}.sql 压缩到 ${db_name}_${time}.tar.gz 结束***"
else
echo "Warning: SQL backup file ${backup_dir}/${db_name}_${time}.sql not found, skipping compression."
fi
if [ -f "${backup_dir}/${db_name}_${time}.dmp" ]; then
tar -zcvf "${backup_dir}/${db_name}_${time}_dmp.tar.gz" "${backup_dir}/${db_name}_${time}.dmp"
echo -e "***${db_name}_${time}.dmp 压缩到 ${db_name}_${time}_dmp.tar.gz 结束***"
else
echo "Warning: DMP backup file ${backup_dir}/${db_name}_${time}.dmp not found, skipping compression."
fi
echo -e "***压缩备份文件结束***"
echo -e "***开始清理旧文件***"
cd "$backup_dir" || { echo "Error: Could not change to backup directory $backup_dir"; exit 1; }
find . -type f -mtime +180 -name '*.sql' -delete
find . -type f -mtime +180 -name '*.dmp' -delete
find . -type f -mtime +180 -name '*.tar.gz' -delete
echo -e "***旧文件清理结束***"
echo -e "***备份脚本执行完毕***"执行脚本
chmod +x backup_opengauss.sh
./backup_opengauss.sh部署elasticsearch
方法一:docker直接跑
根据当前服务器情况修改ES_JAVA_OPTS环境变量 访问服务器对应的9200端口即可
docker run -it -d --name elasticsearch -e "discovery.type=single-node" -e "ES_JAVA_OPTS=-Xms512m -Xmx1024m" -p 9200:9200 -p 9300:9300 elasticsearch:7.17.6安装中文分词器插件
进入容器
docker exec -it elasticsearch bash安装插件的方式
联网安装
联网安装插件(这是官方ceo仓库的路径)
elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.17.6/elasticsearch-analysis-ik-7.17.6.zip联网安装插件(这是官方仓库的路径)
elasticsearch-plugin install https://github.com/infinilabs/analysis-ik/releases/download/v7.17.6/elasticsearch-analysis-ik-7.17.6.zip本地zip安装
本地安装zip插件
elasticsearch-plugin install file:///usr/share/elasticsearch/plugins/elasticsearch-analysis-ik-7.17.6.zip查看已安装的插件
命令查看
elasticsearch-plugin listapi查看
http://localhost:9200/_cat/pluginsexit退出容器后重启容器
docker restart elasticsearch方法二:dockercompose
先下载好分词器插件的zip包,地址如下
https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.17.6/elasticsearch-analysis-ik-7.17.6.zipdockerfile
FROM elasticsearch:7.17.6
# 创建目录
RUN mkdir -p /usr/share/elastic
# 复制IK分词器到指定目录
COPY elasticsearch-analysis-ik-7.17.6.zip /usr/share/elastic/
# 安装分词器
RUN elasticsearch-plugin install file:///usr/share/elastic/elasticsearch-analysis-ik-7.17.6.zip --batch
# 清理安装包
RUN rm -f /usr/share/elastic/elasticsearch-analysis-ik-7.17.6.zipdockercompose
version: "3"
name: test
services:
elasticsearch:
build:
context: .
dockerfile: Dockerfile
container_name: elasticsearch
environment:
- discovery.type=single-node
- ES_JAVA_OPTS=-Xms512m -Xmx1024m
ports:
- "9200:9200"
- "9300:9300"
networks:
- test
deploy:
resources:
limits:
memory: 1G
reservations:
memory: 512M
kibana:
image: kibana:7.17.6
container_name: kibana
environment:
- elasticsearch.hosts=http://elasticsearch:9200
ports:
- "5601:5601"
depends_on:
- elasticsearch
networks:
- test
deploy:
resources:
limits:
memory: 1G
reservations:
memory: 512M
networks:
test:部署kibana
需要和es版本对应 --link elasticsearch:es表示容器互联,即容器kibana连接到elasticsearch。
docker run --name kibana -p 5601:5601 --link elasticsearch:es -e "elasticsearch.hosts=http://es:9200" -d kibana:7.17.6部署jenkins
最新版
docker run \
-d \
-u root \
--privileged \
-p 8080:8080 \
-p 50000:50000 \
--name jenkins \
--restart=always \
-v /data/jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $(which docker):/usr/bin/docker \
-v /etc/localtime:/etc/localtime \
-e TZ=Asia/Shanghai \
jenkins/jenkins:latest查看密码
cat /data/jenkins_home/secrets/initialAdminPassword优化版
docker run \
-d \
-u root \
--privileged \
-p 8080:8080 \
-p 50000:50000 \
--name jenkins \
--restart=unless-stopped \
--memory="1g" \
--memory-swap="1g" \
--cpus="1" \
-v /data/jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
-v $(which docker):/usr/bin/docker \
-v /etc/localtime:/etc/localtime \
-e TZ=Asia/Shanghai \
-e JAVA_OPTS="-Xmx512m -Xms256m -XX:MaxMetaspaceSize=128m" \
jenkins/jenkins:lts-jdk17主要优化内容
- --memory="1g": 限制内存使用为1GB
- --memory-swap="1g": 限制交换空间为1GB
- --cpus="1": 限制使用1个CPU核心
- -Xmx512m: 最大堆内存设置为512MB
- -Xms256m: 初始堆内存设置为256MB
- -XX:MaxMetaspaceSize=128m: 限制元空间大小为128MB
部署prometheus和grafana
dockercompose
# 这个compose文件是用来架设监控应用的,需要对prometheus和grafana的数据卷权限进行授权
services:
# Prometheus:时序数据库,用于存储和查询监控指标
prometheus:
image: prom/prometheus
container_name: prometheus
ports:
- "9091:9090" # 将容器的9090端口映射到主机的9091端口
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml # 挂载配置文件
- /home/docker_volums/prometheus_volumes/data:/prometheus/data # 数据持久化
command:
- '--config.file=/etc/prometheus/prometheus.yml' # 指定配置文件路径
- '--web.enable-lifecycle' # 启用热重载功能
- '--storage.tsdb.retention.time=15d' # 数据保留15天
- '--storage.tsdb.path=/prometheus/data' # 数据存储路径
- '--storage.tsdb.retention.size=5GB' # 限制数据存储大小为5GB
user: "65534:65534" # 使用nobody用户运行,解决权限问题
extra_hosts:
- "host.docker.internal:host-gateway" # 允许容器访问宿主机
networks:
- bzl
# Grafana:可视化平台,用于展示监控数据
grafana:
image: grafana/grafana
container_name: grafana
ports:
- "3000:3000" # Grafana Web界面端口
volumes:
- /home/docker_volums/grafana_volumes:/var/lib/grafana # 数据持久化
- /home/docker_volums/grafana_volumes/provisioning:/etc/grafana/provisioning # 配置文件
user: "472:472" # 使用grafana用户运行
environment:
- GF_SECURITY_ADMIN_USER=admin # 管理员用户名
- GF_SECURITY_ADMIN_PASSWORD=admin123 # 管理员密码
- GF_DEFAULT_LANGUAGE=zh-CN # 设置中文界面
- GF_DATE_FORMATS_DEFAULT_TIMEZONE=browser # 使用浏览器时区
- TZ=Asia/Shanghai # 设置时区
- GF_PATHS_DATA=/var/lib/grafana
- GF_PATHS_PROVISIONING=/etc/grafana/provisioning
- GF_DASHBOARDS_MIN_REFRESH_INTERVAL=30s # 仪表盘最小刷新间隔
- GF_USERS_ALLOW_SIGN_UP=false # 禁止用户注册
- GF_AUTH_ANONYMOUS_ENABLED=false # 禁用匿名访问
depends_on:
- prometheus
networks:
- bzl
# 网络配置
networks:
bzl:
name: bzl
external: true # 使用外部已存在的网络坑点,数据卷没有权限,需要手动授权
设置prometheus目录所有权为 nobody(uid=65534)
sudo chown -R 65534:65534 /home/docker_volums/prometheus_volumes
sudo chmod -R 755 /home/docker_volums/prometheus_volumes设置 Grafana 目录权限 (Grafana 使用 uid=472)
sudo chown -R 472:472 /home/docker_volums/grafana_volumes
sudo chmod -R 755 /home/docker_volums/grafana_volumes部署wireguard
需要将
10.2.7.56替换为你的ip或域名;将'<🚨YOUR_ADMIN_PASSWORD_HASH>'替换为你生成的密码
# 生成你的密码($需要双写转义)
docker run --rm -it ghcr.io/wg-easy/wg-easy wgpw 'YOUR_PASSWORD'
# 例如生成PASSWORD_HASH='$$2b$$12$$coPqCsPtcFO.Ab99xylBNOW4.Iu7OOA2/ZIboHN6/oyxca3MWo7fW' // literally YOUR_PASSWORDservices:
wg-easy:
container_name: wg-easy
image: ghcr.io/wg-easy/wg-easy:latest
environment:
# 必需的配置
- WG_HOST=10.2.7.56 # 替换为你的服务器公网IP或域名
- PASSWORD_HASH='<🚨YOUR_ADMIN_PASSWORD_HASH>' # 替换为你的bcrypt密码哈希
# 可选配置
- PORT=51821 # Web UI端口
- WG_PORT=51820 # WireGuard端口
- WG_DEFAULT_ADDRESS=192.168.110.x
- WG_DEFAULT_DNS=114.114.114.114 # 可以设置多个DNS,用逗号分隔
# - WG_ALLOWED_IPS=0.0.0.0/0, ::/0
- WG_ALLOWED_IPS=192.168.110.0/24 # 包含了服务器网段
# 可选功能开关
- LANG=en # Web UI 语言
- UI_TRAFFIC_STATS=true # 启用流量统计
- UI_CHART_TYPE=1 # 图表类型:0=禁用, 1=折线图, 2=区域图, 3=柱状图
- WG_ENABLE_ONE_TIME_LINKS=false # 一次性链接功能
- UI_ENABLE_SORT_CLIENTS=true # 允许客户端排序
volumes:
- ~/.wg-easy:/etc/wireguard # 配置文件存储位置
- /lib/modules:/lib/modules:ro # 添加内核模块挂载
ports:
- "51820:51820/udp" # WireGuard 端口
- "51821:51821/tcp" # Web UI 端口
cap_add:
- NET_ADMIN
- SYS_MODULE
privileged: true
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv4.ip_forward=1
restart: unless-stopped# 如果需要让用户可以访问vpn端的服务,请按照下面的格式配置转发
- WG_ALLOWED_IPS=192.168.110.0/24, 10.2.7.0/24 # 包含了服务器网段
- WG_ENABLE_EXPIRES_TIME=true # 启用客户端过期时间
- WG_POST_UP=iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE; iptables -t nat -A PREROUTING -d 192.168.110.1 -p tcp --dport 8080 -j DNAT --to-destination 10.2.7.56:8080; iptables -t nat -A PREROUTING -d 192.168.110.1 -p tcp --dport 80 -j DNAT --to-destination 10.2.7.56:80
- WG_POST_DOWN=iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE; iptables -t nat -D PREROUTING -d 192.168.110.1 -p tcp --dport 8080 -j DNAT --to-destination 10.2.7.56:8080; iptables -t nat -D PREROUTING -d 192.168.110.1 -p tcp --dport 80 -j DNAT --to-destination 10.2.7.56:80docker run --detach \
--name wg-easy \
--env LANG=de \
--env WG_HOST=10.2.7.56 \
--env PASSWORD_HASH='<🚨YOUR_ADMIN_PASSWORD_HASH>' \
--env PORT=51821 \
--env WG_PORT=51820 \
--env WG_DEFAULT_ADDRESS=192.168.110.x \
--env WG_DEFAULT_DNS=114.114.114.114 \
--env WG_ALLOWED_IPS=192.168.110.0/24, 10.2.7.0/24 \
--volume ~/.wg-easy:/etc/wireguard \
--publish 51820:51820/udp \
--publish 51821:51821/tcp \
--cap-add NET_ADMIN \
--cap-add SYS_MODULE \
--sysctl 'net.ipv4.conf.all.src_valid_mark=1' \
--sysctl 'net.ipv4.ip_forward=1' \
--restart unless-stopped \
ghcr.io/wg-easy/wg-easy部署ollama
docker run -id --name=ollama -p 11434:11434 -v F:\ollama_data:/root/.ollama ollama/ollamaservices:
ollama:
image: ollama/ollama:latest
container_name: ollama
ports:
- "11434:11434"
volumes:
- F:\ollama_data:/root/.ollama
deploy:
resources:
limits:
memory: 20G # 限制内存使用为20GB
networks:
- ollama
restart: unless-stopped
ollama-webui:
image: ghcr.io/ollama-webui/ollama-webui:main
container_name: ollama-webui
ports:
- "3000:8080"
environment:
- OLLAMA_API_BASE_URL=http://ollama:11434/api
depends_on:
- ollama
networks:
- ollama
restart: unless-stopped
networks:
ollama:
name: ollamaservices:
# Ollama 服务配置
ollama:
# 指定容器名称
container_name: ollama
# 使用的镜像及版本
image: ollama/ollama:latest
# 端口映射,格式为 "主机端口:容器端口"
ports:
- "11434:11434"
# 数据卷挂载,用于持久化存储模型和配置
volumes:
- F:\ollama_data:/root/.ollama
# deploy 块用于配置容器的部署选项,特别是硬件资源相关的设置
deploy:
resources:
reservations: # 资源预留配置
devices: # 设备配置
- driver: nvidia # 指定使用 NVIDIA 驱动
count: all # 使用所有可用的 GPU
capabilities: [gpu] # 启用 GPU 功能
# 容器重启策略:除非手动停止,否则总是重启
restart: unless-stopped
# environment 块用于设置容器的环境变量
environment:
# 指定 NVIDIA 驱动能力,compute 用于计算,utility 用于工具支持
- NVIDIA_DRIVER_CAPABILITIES=compute,utility
# 允许容器访问所有 GPU 设备
- NVIDIA_VISIBLE_DEVICES=all
# 添加运行时配置
runtime: nvidia部署jre服务器
注意
- 生成UUID
- 使用时需要关闭在线模式,如果无法关闭,请删除用户文件夹下的
.jrebel文件夹
新的开源项目
docker run --restart=always -id -p 12345:12345 --name jrebel-license-active-server yuxiaoyao520/jrebel-license-active-server:latest使用(服务器地址和邮箱)
https://127.0.0.1:123456/ec190ca9-e7b1-4a8c-ad0a-4267c82a0a11
123456789@qq.com老项目(现在用不了了,但是纪念一下)
docker run --restart=always -dit --name=jreber -p 8888:8888 qierkang/golang-reverseproxy防火墙命令速查
常用dockerfile写法
FROM openjdk:8
# 作者信息
LABEL maintainer="bzl"
# 设置时区
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 创建必要的目录
RUN mkdir -p /app/logs /app/uploadtmp /app
# 设置工作目录
WORKDIR /app
# 将构建的 jar 文件添加到容器中
COPY ./target/bzl-boot-1.0.0.jar ./bzl-boot-1.0.0.jar
# 暴露应用的端口
EXPOSE 8083
# 设置容器启动时执行的命令(按照需求选择下面的内容)
# 如果只需要docker显示日志,请使用这条(不能换行哦)
CMD ["java", "-Djava.io.tmpdir=/app/uploadtmp", "-Duser.timezone=GMT+08", "-jar", "bzl-boot-1.0.0.jar"]
# 如果不需要docker展示日志,而是将日志保存到日志目录,请使用这条
#CMD ["sh", "-c", "java -Djava.io.tmpdir=/app/uploadtmp -Duser.timezone=GMT+08 -jar bzl-boot-1.0.0.jar > logs/catalina.out 2>&1"]
# 如果既要docker展示日志,又要本地存储日志,请使用这条
#CMD ["sh", "-c", "java -Djava.io.tmpdir=/app/uploadtmp -Duser.timezone=GMT+08 -jar bzl-boot-1.0.0.jar | tee logs/catalina.out"]健康检查例子
使用wget检查
FROM nginx:alpine
COPY .vitepress/dist /usr/share/nginx/html
HEALTHCHECK --interval=1s --timeout=3s \
CMD wget -q --spider http://localhost:80/ || exit 1
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]- wget: 一个下载工具
- -q: quiet 模式,不输出任何信息
- --spider: 不下载内容,只检查 URL 是否存在/可访问
多段构建案例
as用于起别名,别名可以在其他阶段通过--from=别名来指定,如果不起别名,则阶段是从0开始,例如取第一个阶段是用--from=0
FROM node:16 as build
WORKDIR /app
COPY. /app
RUN npm install
RUN npm run build
FROM nginx:latest
COPY --from=build /app/dist /usr/share/nginx/html常用dockercompose写法
使用include将通用的docker-compose文件引入进来
docker-compose
name: 项目名_project #这个配置用于将前端和后端的项目名统一,防止由于两个dockercompose导致的网络名称不一致的问题
include:
- path: docker-compose-base.yml
services:
# 后端服务配置
bzl_backend:
build:
context: ./web # 指定构建上下文目录
dockerfile: Dockerfile-local # 指定用于构建的 Dockerfile 文件
image: bzl_boot:1.0 # 构建后的镜像名称和标签
container_name: bzl_backend # 容器名称
healthcheck:
# 这里的/项目名-boot需要和你项目里的server.servlet.context-path一致
test: [ "CMD-SHELL", "curl -f http://localhost:8083/项目名-boot/actuator/health || exit 1" ]
start_period: 65s
interval: 30s
timeout: 10s
retries: 3
restart: on-failure
depends_on: # 定义服务依赖关系
elasticsearch:
condition: service_healthy # 等待 elasticsearch 服务健康检查通过
rabbitmq:
condition: service_started # 等待 rabbitmq 服务启动
redis:
condition: service_started # 等待 redis 服务启动
opengauss:
condition: service_started # 等待 opengauss 服务启动
minio:
condition: service_started # 等待 minio 服务启动
ports:
- "8083:8083" # 端口映射,将容器的 8083 端口映射到主机的 8083 端口
networks:
- bzl # 将服务连接到 bzl 网络
networks:
bzl: # 定义容器网络
name: bzl
# 如果要加入集群,请开启下面两项配置
# driver: overlay
# attachable: truedocker-compose-base
services:
# RabbitMQ 消息队列服务
rabbitmq:
image: rabbitmq:latest # 使用最新版本的 RabbitMQ 镜像
container_name: rabbit # 容器名称
ports:
- 15672:15672 # Web 管理界面端口
- 5672:5672 # AMQP 协议端口
restart: on-failure:5 # 失败时最多重启 5 次
networks:
- bzl # 使用自定义网络 bzl
# Redis 缓存服务
redis:
image: redis # 使用 Redis 官方镜像
container_name: redis
ports:
- 16379:6379 # Redis 服务端口,主机端口映射为 16379
restart: on-failure:5
networks:
- bzl
# OpenGauss 数据库服务
opengauss:
image: enmotech/opengauss-lite:5.1.0 # 使用 OpenGauss 轻量版
container_name: opengauss
ports:
- 15432:5432 # 数据库端口
volumes:
- D:\app_data\docker_volumes:/var/lib/opengauss # 数据持久化存储
environment:
- GS_PASSWORD=Secretpassword@123 # 设置数据库密码
privileged: true # 使用特权模式运行
restart: on-failure:5
networks:
- bzl
# MinIO 对象存储服务
minio:
image: quay.io/minio/minio # MinIO 官方镜像
container_name: minio
ports:
- 9000:9000 # API 端口
- 9090:9090 # Console 控制台端口
environment:
- MINIO_ROOT_USER=minioadmin # MinIO root 用户名
- MINIO_ROOT_PASSWORD=minioadmin # MinIO root 密码
volumes:
- D:\app_data\docker_volumes:/data # 数据持久化存储
command: server /data --console-address ":9090" # 启动命令,指定控制台地址
restart: on-failure:5
networks:
- bzl
# Elasticsearch 搜索引擎服务
elasticsearch:
build:
context: ./es # 构建上下文目录
dockerfile: Dockerfile-es # 自定义的 Dockerfile
container_name: elasticsearch
environment:
- discovery.type=single-node # 单节点模式
- ES_JAVA_OPTS=-Xms512m -Xmx1024m # JVM 内存设置
ports:
- 9200:9200 # HTTP REST API 端口
- 9300:9300 # 节点间通信端口
networks:
- bzl
deploy:
resources:
limits:
memory: 1G # 内存限制
reservations:
memory: 512M # 内存预留
ulimits:
memlock:
soft: -1 # 取消内存锁定限制
hard: -1
healthcheck: # 健康检查配置
test: [ "CMD-SHELL", "curl http://localhost:9200" ]
interval: 5s # 检查间隔
timeout: 5s # 超时时间
retries: 10 # 重试次数
# Kibana 可视化界面
kibana:
image: kibana:7.17.6 # 使用特定版本的 Kibana
container_name: kibana
environment:
- elasticsearch.hosts=http://elasticsearch:9200 # 连接 ES 地址
ports:
- 5601:5601 # Kibana Web 界面端口
depends_on: # 依赖 ES 服务
elasticsearch:
condition: service_healthy # 等待 ES 健康检查通过
networks:
- bzl
deploy:
resources:
limits:
memory: 1G # 内存限制
reservations:
memory: 512M # 内存预留
# 自定义网络配置
networks:
bzl:
name: bzl # 网络名称
# 如果要加入集群,请开启下面两项配置
# driver: overlay
# attachable: true常用排错方法
容器起不来
查看容器日志
docker logs 容器名项目中看不到图片
docker查看镜像详细信息,查看镜像的基本版本是否兼容
docker inspect 镜像名称安装docker
升级docker重新再执行一遍卸载和安装
官方安装方式,使用dnf安装docker
卸载老版本docker
如果没有dnf,请先安装dnf
sudo dnf remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine设置docker仓库
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo安装Docker Engine
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin# 查看可以安装的版本,会列出可以安装的版本,例如: 3:27.5.0-1.el9
dnf list docker-ce --showduplicates | sort -r
# 安装对应版本,请将<VERSION_STRING>替换为对应的版本号
sudo dnf install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io docker-buildx-plugin docker-compose-plugin启动Docker Engine并配置docker开机启动
sudo systemctl enable --now docker验证docker是否安装成功
sudo docker run hello-world使用yum的安装方式
sudo yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
sudo yum install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable docker --now快捷脚本方法
2024年11月使用的安装方式 脚本使换源更简单 - LinuxMirrors 自动安装docker
bash <(curl -sSL https://linuxmirrors.cn/docker.sh)docker加上代理
"proxies": {
"http-proxy": "http://127.0.0.1:10809",
"https-proxy": "http://127.0.0.1:10809"
}如果加上代理之后还是拉不下来,就多重试几次
镜像加速
有代理就不需要这个
registry-mirrors配置了
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": [
"https://1ms.run",
"https://mirror.ccs.tencentyun.com",
"https://docker.fxxk.dedyn.io",
"https://dockerproxy.com",
"https://docker.m.daocloud.io",
"https://quay.io"
],
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
}
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker候选源
"https://docker.1panel.live"镜像源地址延迟测试
官方镜像仓库
hub.docker.comdocker修改数据存储目录
查看docker当前数据目录位置
docker info --format '{{.DockerRootDir}}'停止docker
sudo systemctl stop docker编辑daemon.json文件
vim /etc/docker/daemon.json加上指定位置的配置
{
"registry-mirrors": ["https://docker.1ms.run"],
"data-root": "/home/docker"
}将默认目录的文件拷贝到目标目录,docker默认不会迁移容器
cp -r /var/lib/docker /home/启动docker
sudo systemctl start docker完全卸载 Docker
方法一
sudo systemctl stop docker
sudo systemctl disable docker
sudo yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine方法二
查看已安装的docker相关的软件包
yum list installed | grep docker例如执行上述语句后的结果
containerd.io.x86_64 1.6.26-3.1.el7 @docker-ce-stable
docker-buildx-plugin.x86_64 0.11.2-1.el7 @docker-ce-stable
docker-ce.x86_64 3:24.0.7-1.el7 @docker-ce-stable
docker-ce-cli.x86_64 1:24.0.7-1.el7 @docker-ce-stable
docker-ce-rootless-extras.x86_64 24.0.7-1.el7 @docker-ce-stable
docker-compose-plugin.x86_64 2.21.0-1.el7 @docker-ce-stable如果结果和上面的一样,可以执行下述语句
sudo yum remove docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-runc方法三
找到docker
which docker
docker --version删除所有 Docker 相关文件和目录
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
sudo rm -rf /usr/bin/docker
sudo rm -rf /etc/docker帮助
# 直接敲
docker
# 或者用下面这个
docker 命令 --helpDocker 进程相关命令
# 启动docker服务:
systemctl start docker
# 停止docker服务:
systemctl stop docker
# 重启docker服务:
systemctl restart docker
# 查看docker服务状态:
systemctl status docker
# 设置开机启动docker服务:
systemctl enable dockerDocker 镜像相关命令
# 查看镜像: 查看本地所有的镜像
docker images
docker images –q # 查看所用镜像的id
# 搜索镜像:从网络中查找需要的镜像
docker search 镜像名称
# 拉取镜像:从Docker仓库下载镜像到本地,镜像名称格式为 名称:版本号,如果版本号不指定则是最新的版本。如果不知道镜像版本,可以去docker hub 搜索对应镜像查看。
docker pull 镜像名称
docker pull 镜像名称:版本号
# 删除镜像: 删除本地镜像
docker rmi 镜像id # 删除指定本地镜像
docker rmi `docker images -q` # 删除所有本地镜像
# 查看镜像信息(会以json显示)
docker inspect 镜像名
# 提交容器变化打成一个新的镜像
docker commit -m "update index.html" mynginx mynginx:v1.0
# 保存镜像到本地压缩文件
docker save -o 文件名 镜像名:版本号
docker save -o nginx.tar nginx:latest
# 加载tar包镜像(例如加载nacos.tar)
docker load -i nacos.tar
# 登录 docker hub
docker login
# 重新给镜像打标签
docker tag mynginx:v1.0 leifengyang/mynginx:v1.0
# 推送镜像
docker push leifengyang/mynginx:v1.0Docker 容器相关命令
查看容器
# 查看正在运行的容器
docker ps
# 查看所有容器
docker ps –a
# 显示最近创建的容器
docker ps –l
# 显示最近n个创建的容器
docker ps –n
# 静默模式,只显示容器编号
docker ps –q
# 格式化输出
docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"创建并启动容器
# 基本格式
docker run 参数
# 设置自启动
docker run --restart=always 容器名称或ID
# 交互式容器的创建
docker run -it --name=c1 centos:7 /bin/bash
# 守护式容器的创建
docker run -id --name=c1 centos:7 /bin/bash
# 端口号映射(主机端口:容器端口)
docker run -id --name=nginx -p 80:80 nginx /bin/bash参数说明
| 参数 | 说明 |
|---|---|
| -i | 保持容器运行。通常与 -t 同时使用。加入 -it 这两个参数后,容器创建后自动进入容器中,退出容器后,容器自动关闭。 |
| -t | 为容器重新分配一个伪输入终端,通常与 -i 同时使用。 |
| -d | 以守护(后台)模式运行容器。创建一个容器在后台运行,需要使用 docker exec 进入容器。退出后,容器不会关闭。 |
| -it | 创建的容器一般称为交互式容器。 |
| -id | 创建的容器一般称为守护式容器。 |
| --name | 为创建的容器命名。 |
容器操作
启动容器
docker start 容器名称或ID停止容器
docker stop 容器名称或ID删除容器
# 单个删除(如果容器是运行状态则删除失败,需要停止容器才能删除)
docker rm 容器名称(或ID)
# 强制删除
docker rm -f 容器名称(或ID)
# 强制删除所有容器
docker rm -f ${docker ps -a -q}
# 一次删除多个容器实例(建议别用)
docker ps -a -q|xargs docker rm进入容器
# 进入容器(用这种方式进入容器,在退出容器后,容器不会关闭)
docker exec 参数 容器名 进入容器后的操作
## 例如(mysql -uroot -p表示进到mysql容器后执行的命令)
docker exec -it mysql mysql -uroot -p
## 例如(/bin/bash表示进到nginx容器后执行的命令)
docker exec -it nginx /bin/bash退出容器
# run进容器,用该命令退出容器后,容器停止
# exec进容器,不会停止
exit
# run进容器,用该命令退出容器后,容器不停止
ctrl+p+q查看容器信息
docker inspect 容器名称或ID查看对应容器日志
docker logs -f 容器名
# 例如
docker logs -f nacosDocker 容器的数据卷
理解

基本命令
# 创建数据卷
docker volume create
# 查看所有数据卷
docker volume ls
# 删除指定数据卷
docker volume rm
# 查看某个数据卷详情
docker volume inspect
# 清除数据卷
docker volume prune运行时创建
docker run ... –v 宿主机目录(文件):容器内目录(文件) ...
# 例如(/root/data为宿主机数据存放位置,/root/data_container为容器中数据存放位置)
docker run -it --name=c1 -v /root/data:/root/data_container centos:7 /bin/bash
# 例如(html是宿主机数据卷存放位置的别名,默认会放到/var/lib/docker/volumes/html中)
docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx
多容器进行数据交换
将c1和c2挂载到数据源容器c3上,并且c3挂载到主机上 
# 1. 创建启动c3数据卷容器,使用 –v 参数 设置数据卷
docker run –it --name=c3 –v /volume centos:7 /bin/bash
# 2. 创建启动 c1 c2 容器,使用 –-volumes-from 参数 设置数据卷
docker run –it --name=c1 --volumes-from c3 centos:7 /bin/bash
docker run –it --name=c2 --volumes-from c3 centos:7 /bin/bashdockerfile
介绍
由于制作镜像的过程中,需要逐层处理和打包,比较复杂,所以Docker就提供了自动打包镜像的功能。我们只需要将打包的过程,每一层要做的事情用固定的语法写下来,交给Docker去执行即可。而这种记录镜像结构的文件就称为Dockerfile
https://docs.docker.com/engine/reference/builder/指令

使用
1.0后面有一小个下划线,其实是个空格,只是为了让我方便看,然后显示出来的
例子

网络
介绍
容器的网络IP其实是一个虚拟的IP,其值并不固定与某一个容器绑定,如果我们在开发时写死某个IP,而在部署时很可能MySQL容器的IP会发生变化,连接会失败。
https://docs.docker.com/engine/reference/commandline/network/为什么要用网络
在docker的默认网络中,容器一被启动,就会按顺序被分配一个网络,如果这次启动mysql时分配的是172.17.0.3,下次如果redis先启动,则可能会把改地址占用了,要解决由于自动分配网络导致连接失败的问题,可以使用docker中的network功能,只要将容器加到自己分配的网络中, 那么我们就可以直接用容器别名来访问该容器,这就解决了我们要使用ip来访问该容器的问题
在自定义网络中,可以给容器起多个别名,默认的别名是容器名本身 在同一个自定义网络中的容器,可以通过别名互相访问
命令
# 创建一个网络
docker network create
# 查看所有网络
docker network ls
# 删除指定网络
docker network rm
# 清除未使用的网络
docker network prune
# 使指定容器连接加入某网络
docker network connect
# 使指定容器连接离开某网络
docker network disconnect
# 查看网络详细信息
docker network inspect例子
# 在运行时加入网络(这样创建,不会加入默认网络,只会加入指定网络)
# 要先创建这个网络!!!
docker -run -d --name 容器别名 -p 8080:8080 --network 网络名称 容器名称项目部署案例(将相关文件移动到/root下)
# 项目参考链接
https://b11et3un53m.feishu.cn/wiki/MWQIw4Zvhil0I5ktPHwcoqZdnec部署后端
SpringBoot配置文件()
在容器里使用则配置为容器名 
用maven打包项目(选择package)

编写dockerfile
# 基础镜像
FROM openjdk:11.0-jre-buster
# 设定时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 拷贝jar包
COPY hm-service.jar /app.jar
# 入口
ENTRYPOINT ["java", "-jar", "/app.jar"]将dockerfile文件和打好的jar包移动到需要放置的位置,本次放置在、root下
docker创建网络
docker network create hm-netdocker运行mysql
# 有配置文件,就先把配置文件先移动到数据卷里面,然后再构建
docker run -d \
--name mysql \
-p 3306:3306 \
-e TZ=Asia/Shanghai \
-e MYSQL_ROOT_PASSWORD=123 \
-v /root/mysql/data:/var/lib/mysql \
-v /root/mysql/conf:/etc/mysql/conf.d \
-v /root/mysql/init:/docker-entrypoint-initdb.d \
--network hm-net\
mysql构建java项目镜像并运行
# 打包镜像
docker build -t hmall .
# 运行镜像
docker run -d --name hm -p 8080:8080 --network hm-net hmall打开linux的防火墙对应端口,然后访问hi接口

部署前端
部署nginx
# 将配置文件和前端打包好的文件粘贴到数据卷对应位置
docker run -d \
--name nginx \
-p 18080:18080 \
-p 18081:18081 \
-v /root/nginx/html:/usr/share/nginx/html \
-v /root/nginx/nginx.conf:/etc/nginx/nginx.conf \
--network hm-net \
nginxDockerCompose
介绍
Docker Compose通过一个单独的docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器,帮助我们实现多个相互关联的Docker容器的快速部署。 
docker和docker compose语法对比

命令
| 类型 | 参数或指令 | 说明 |
|---|---|---|
| Options | -f | 指定compose文件的路径和名称 |
| -p | 指定project名称。project就是当前compose文件中设置的多个service的集合,是逻辑概念 | |
| Commands | up | 创建并启动所有service容器 |
| down | 停止并移除所有容器、网络 | |
| ps | 列出所有启动的容器 | |
| logs | 查看指定容器的日志 | |
| stop | 停止容器 | |
| start | 启动容器 | |
| restart | 重启容器 | |
| top | 查看运行的进程 | |
| exec | 在指定的运行中容器中执行命令 |
案例(Redis主从同步集群)
#自定义网络
docker network create mynet
#主节点
docker run -d -p 6379:6379 \
-v /app/rd1:/bitnami/redis/data \
-e REDIS_REPLICATION_MODE=master \
-e REDIS_PASSWORD=123456 \
--network mynet --name redis01 \
bitnami/redis
#从节点
docker run -d -p 6380:6379 \
-v /app/rd2:/bitnami/redis/data \
-e REDIS_REPLICATION_MODE=slave \
-e REDIS_MASTER_HOST=redis01 \
-e REDIS_MASTER_PORT_NUMBER=6379 \
-e REDIS_MASTER_PASSWORD=123456 \
-e REDIS_PASSWORD=123456 \
--network mynet --name redis02 \
bitnami/redis案例(部署wordpress)
命令启动
#创建网络
docker network create blog
#启动mysql
docker run -d -p 3306:3306 \
-e MYSQL_ROOT_PASSWORD=123456 \
-e MYSQL_DATABASE=wordpress \
-v mysql-data:/var/lib/mysql \
-v /app/myconf:/etc/mysql/conf.d \
--restart always --name mysql \
--network blog \
mysql:8.0
#启动wordpress
docker run -d -p 8080:80 \
-e WORDPRESS_DB_HOST=mysql \
-e WORDPRESS_DB_USER=root \
-e WORDPRESS_DB_PASSWORD=123456 \
-e WORDPRESS_DB_NAME=wordpress \
-v wordpress:/var/www/html \
--restart always --name wordpress-app \
--network blog \
wordpress:latestdocker-compose启动
name: myblog
services:
mysql:
container_name: mysql
image: mysql:8.0
ports:
- "3306:3306"
environment:
- MYSQL_ROOT_PASSWORD=123456
- MYSQL_DATABASE=wordpress
volumes:
- mysql-data:/var/lib/mysql
- /app/myconf:/etc/mysql/conf.d
restart: always
networks:
- blog
wordpress:
image: wordpress
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_USER: root
WORDPRESS_DB_PASSWORD: 123456
WORDPRESS_DB_NAME: wordpress
volumes:
- wordpress:/var/www/html
restart: always
networks:
- blog
depends_on:
- mysql
volumes:
mysql-data:
wordpress:
networks:
blog:案例(部署黑马商城项目)
直接部署
目录为/root 将数据卷对应文件、jar包、dockerfile、docker-compose.yml文件移到/root目录下
- DockerFile文件内容
# 基础镜像(这里可以改为java:openjdk-8,需要的话自己改一下)
FROM openjdk:11.0-jre-buster
# 设定时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
# 拷贝jar包
COPY hm-service.jar /app.jar
# 入口
ENTRYPOINT ["java", "-jar", "/app.jar"]- DockerCompose文件内容
version: "3.8"
services:
mysql:
image: mysql
container_name: mysql
ports:
- "3306:3306"
environment:
TZ: Asia/Shanghai
MYSQL_ROOT_PASSWORD: 123
volumes:
- "./mysql/conf:/etc/mysql/conf.d"
- "./mysql/data:/var/lib/mysql"
- "./mysql/init:/docker-entrypoint-initdb.d"
networks:
- hm-net
hmall:
build:
context: .
dockerfile: Dockerfile
container_name: hmall
ports:
- "8080:8080"
networks:
- hm-net
depends_on:
- mysql
nginx:
image: nginx
container_name: nginx
ports:
- "18080:18080"
- "18081:18081"
volumes:
- "./nginx/nginx.conf:/etc/nginx/nginx.conf"
- "./nginx/html:/usr/share/nginx/html"
depends_on:
- hmall
networks:
- hm-net
networks:
hm-net:
name: hmall- dockercompose相关命令
# 启动所有容器
docker compose up -d
# 停止并删除所有容器
docker compose down-d表示后台运行
测试
开启防火墙的18080端口,然后访问登录界面 
账号:jack
密码:123成功登录 
假设已经使用dockercompose启动了所有容器,但是要重新部署hmall
# 停止 hmall 容器
docker compose stop hmall
# 移除 hmall 容器
docker compose rm -f hmall
# 重新构建 hmall 镜像(如有必要)
docker compose build hmall
# 重新启动 hmall 容器
docker compose up -d hmall
# 检查服务状态
docker compose ps假设dockercompose只启动mysql容器
# 启动 `mysql` 服务
docker compose up mysql
# 后台启动容器(常用)
docker compose up -d mysql
# 检查服务状态
docker compose ps
# 停止服务
docker compose stop mysql
# 停止并移除容器
docker compose down
# 只移除特定服务
docker compose rm -f mysql
# 查看 mysql 服务的日志
docker compose logs mysqldocker集群
实验环境
- 我现在有两台物理机(内网ip分别为:
10.2.7.56和10.2.7.113),由于子网掩码为24,现在以56和113代表这两台主机,方便区分 - 其中
56为管理节点,113为工作节点,并且两个主机都是单网卡
注意事项
需要确保两台机器的以下端口是开放的,开放端口的的方式,开放端口后还不生效,请重启一下试试
- TCP 2377 - 集群管理通信
- TCP/UDP 7946 - 节点间通信
- UDP 4789 - overlay网络流量
修改各主机的主机名
建议这样做,方便后续管理
# 56
hostnamectl set-hostname master
# 113
hostnamectl set-hostname worker初始化集群
注意
初始化之后,会生成加入工作节点的命令,以及如何生成加入管理节点的命令
在56上初始化集群
docker swarm init --advertise-addr 10.2.7.56上述命令执行完成之后会生成一个用于加入56创建的集群的语句,执行结果如图所示
113作为工作节点加入集群
复制上面生成的命令,并在113上执行,会以
工作节点的形式加入集群
docker swarm join --token SWMTKN-1-2ccybp5pdtxg8g81i3uenj301vutdka4gf37efisf38thz2ohu-5qlfm6hyr8luujn4omb05hhga 10.2.7.56:2377执行结果如图所示
注意:如果需要加入节点的机器上有多张网卡,需要用
--advertise-addr参数指定网卡的ip作为广播地址,例如我的机器b就指定使用ip为10.2.7.113的网卡作为广播地址
docker swarm join --advertise-addr 10.2.7.113 --token SWMTKN-1-2ccybp5pdtxg8g81i3uenj301vutdka4gf37efisf38thz2ohu-5qlfm6hyr8luujn4omb05hhga 10.2.7.56:2377113作为管理节点加入集群
在加入工作节点的下方会生成如何生成加入管理节点的命令(图中黄色那条的命令)
docker swarm join-token manager
复制上面生成的命令,并在113上执行,会以
管理节点的形式加入集群
docker swarm join --advertise-addr 10.2.7.113 --token SWMTKN-1-22ke9z1x10kll41u72n49humagrgwwi4gha2yc6l14lc6li5v2-5wd0wrmxqbvdygufm4ujvrgkm 10.2.7.56:2377查看集群信息
在管理节点(此处为
56)才可查看,结果如下图
docker node ls
只有有管理权限的子节点才能看,如果在子节点
113执行,执行结果如下,113升级为管理节点后
集群管理常用命令
节点管理
查看节点
docker node ls
查看某个节点情况
docker node ps 节点的id或hostname
| 状态 | 说明 |
|---|---|
| active | 正常接受和运行任务、可以部署新的服务、默认的工作状态 |
| drain | 停止接受新任务,现有任务会被转移到其他节点(主要用于:维护节点、升级系统、下线节点) |
| pause | 停止接受新任务、现有任务继续运行(适用于:临时停止调度、不想接收新任务但也不想迁移现有任务) |
将节点升级为管理节点
docker node promote 对应服务器的节点id或hostname将节点降级为管理节点
docker node demote 对应服务器的节点id或hostname节点下线
docker node update --availability drain 对应服务器的节点id或hostname
节点上线
docker node update --availability drain 对应服务器的节点id或hostname
服务管理
通过命令创建服务
用法
docker service create部署visualizer案例
visualizer可以让swarm的服务滚动更新实时显示在UI界面上,便于观察滚动更新过程
docker service create \
--name=viz \
--publish=8080:8080 \
--constraint=node.role==manager \
--mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
dockersamples/visualizer通过docker-compose文件创建服务
TIP
docker stack 会以服务的形式创建,服务名称的格式是:stack名称_服务名称,服务名称为dockercompose文件中services的下一级
部署
# 部署 stack 或更新配置后重新部署 (# my-nginx 是 stack 名称)
docker stack deploy -c docker-compose.yaml my-nginx
# 查看 stack 列表
docker stack ls
# 查看服务状态
docker stack services my-nginx
# 查看任务分布
docker stack ps my-nginx
# 删除 stack
docker stack rm my-nginx
# 查看服务日志
docker service logs my-nginx_nginx
docker stack用法
[root@master stack]# docker stack --help
Usage: docker stack COMMAND
Manage Swarm stacks
Commands:
config Outputs the final config file, after doing merges and interpolations
deploy Deploy a new stack or update an existing stack
ls List stacks
ps List the tasks in the stack
rm Remove one or more stacks
services List the services in the stack
Run 'docker stack COMMAND --help' for more information on a command.指定机器部署
部署命令不变
docker stack deploy -c docker-compose.yaml my-nginx方法一,给节点添加标签,选择带有该标签的机器部署 注意:Docker Swarm 节点标签可以分为内置标签和自定义标签!!!
# 加标签,标签名为deploy,标签值为worker1,这里的worker是指节点的hostname,113的hostname就是叫worker
docker node update --label-add deploy=worker1 worker
# 查看节点标签
docker node inspect workerservices:
nginx:
image: nginx:latest
deploy:
replicas: 4
placement:
constraints:
- node.labels.deploy == worker1 # 使用标签约束内置标签(可以直接用)
placement:
constraints:
- node.hostname == worker1 # 主机名
- node.id == nodeID # 节点ID
- node.role == worker # 节点角色 (manager/worker)
- node.platform.os == linux # 操作系统
- node.platform.arch == x86_64 # 系统架构
- node.labels.zone == east # 自定义标签常用自定义标签
# 环境标签
- node.labels.env == prod # 生产环境
- node.labels.env == test # 测试环境
- node.labels.env == dev # 开发环境
# 区域标签
- node.labels.zone == east # 东区
- node.labels.zone == west # 西区
- node.labels.datacenter == dc1 # 数据中心1
# 硬件标签
- node.labels.disk == ssd # SSD磁盘
- node.labels.cpu == high # 高性能CPU
- node.labels.gpu == true # 包含GPU
# 应用层标签
- node.labels.tier == frontend # 前端服务
- node.labels.tier == backend # 后端服务
- node.labels.tier == database # 数据库服务方法二,使用主机名约束
services:
nginx:
image: nginx:latest
deploy:
replicas: 4
placement:
constraints:
- node.hostname == worker # 使用主机名约束更复杂的约束方式 constraints指硬性约束条件,强制要求部署在主机名为 worker 的节点上 preferences指软性偏好设置,尽量将容器分散在不同 zone 标签的节点上
services:
nginx:
image: nginx:latest
deploy:
replicas: 4
placement:
constraints:
- node.hostname == worker
preferences:
- spread: node.labels.zone# 举例说明
# 如果有多个节点带有不同的 zone 标签:
Node1: zone=zone1
Node2: zone=zone2
Node3: zone=zone3
# 当部署多个副本时,会尽量均匀分布:
Replica1 -> zone1
Replica2 -> zone2
Replica3 -> zone3使用多个约束条件
services:
nginx:
image: nginx:latest
deploy:
replicas: 4
placement:
constraints:
- node.hostname == worker
- node.labels.deploy == worker1
- node.role == worker更新
语法
docker service update --replicas 数量 \
--image 基础镜像 \
--update-delay 时间 \
--update-parallelism 数量 \
服务名- --image 需要更新的镜像
- --update-delay 定义滚动更新的时间间隔(默认0),单位如:s、m、h、ms、1h20m30s即1小时20分30秒
- --update-parallelism 定义并行更新的最大数量(正更新的这些任务不可用)
- --replicas 副本个数
使用案例(之前用stack部署了名为my-nginx的nginx服务,部署,一共4个副本,镜像为nginx:latest,现在更新为nginx:alpine,2个副本)
docker service update --replicas 2 \
--image nginx:alpine \
--update-delay 60s \
--update-parallelism 5 \
my-nginx_nginx注意
使用stack部署的时候,部署完成的服务会在stack的名字后面加上对应的服务名,例如stack名字为my-nginx,部署的服务名为nginx,那最后部署出来的服务名为my-nginx_nginx,因此此处的服务名为my-nginx_nginx
更新前
更新中
在
113上看容器状态
更新后
此时在
113上看容器状态
停止更新
立即停止正在进行的更新
# 暂停更新
docker service update --update-pause nginx
# 或者对于 stack
docker service update --update-pause my-nginx_nginx回滚
回滚到之前的版本
# 回滚服务
docker service update --rollback nginx
# 对于 stack 服务
docker service update --rollback my-nginx_nginx
# 查看回滚状态
docker service ps nginx
使用具体版本回滚
# 回滚到特定镜像版本
docker service update --image nginx:1.22 nginx
# 强制立即更新所有任务
docker service update --force nginx监控和验证
# 查看服务状态
docker service ps nginx
# 查看服务日志
docker service logs nginx
# 查看更新历史
docker service inspect nginx --pretty查看已部署的服务
docker service ls
查看对应服务信息
docker service ps 服务名
查看服务日志
# 在这句后面按下tab可以看到对应的提示docker service logs
# 查看服务日志
docker service logs 服务名
# 查看服务中某个容器日志
docker service logs 容器id
修改服务副本数量
使用scale
# 将副本数改为 3
docker service scale my-nginx_nginx=3
# 同时修改多个服务
docker service scale my-nginx_nginx=3 other_service=2
# 查看结果
docker service ls
docker service ps my-nginx_nginx
使用update
# 更新副本数为 2
docker service update --replicas 2 my-nginx_nginx
# 查看更新过程
docker service ps my-nginx_nginx
# 查看服务详情
docker service inspect my-nginx_nginx
集群部署案例
下面将会以部署nginx为例进行操作
注意
管理节点负责对容器进行编排和管理,包括:创建、启动、停止、重启容器等操作 管理节点为10.2.7.56,工作节点为10.2.7.113
环境准备
创建首页页面(以在113创建为例)
mkdir /home/testSwarm将页面目录拷贝到其他机器(将
113的拷贝到56)
scp -r /home/testSwarm/ root@10.2.7.56:/home/testSwarm
写一个页面
cat <<EOF | sudo tee /home/testSwarm/index.html
<h1>你好swarm!</h1>
EOF部署nginx
注意
- 如果指定只在worker节点上部署,需要加上
--constraint 'node.role==worker'参数,或者在管理节点上将管理节点的状态设置为drain,命令为:docker node update --availability drain 工作节点的id或hostname - 如果需要映射数据卷的话,在哪里部署,哪里就得有对应的数据卷绑定(其他解决方案)
- 部署在一个节点,集群中其他节点也可以通过自己的ip+对应的端口进行访问,例如这个案例中,nginx只部署在10.2.7.113:9999,那通过10.2.7.56:9999也可以访问nginx,它会把这个请求转发到集群内部有这个服务的节点上

通过命令部署
docker service create \
--name nginx \
--replicas 4 \
--mount type=bind,source=/home/testSwarm,target=/usr/share/nginx/html \
-p 9999:80 \
--restart-condition any \
nginx- --replicas 4:4份副本
- --mount:
type=bind,source=/home/testSwarm,target=/usr/share/nginx/html就是平时用的将宿主机目录映射到容器目录type=volume,source=数据卷名字,target=/usr/share/nginx/html就是指定数据卷名字,需要先使用docker volume create 数据卷名字创建数据卷
- --restart-condition:任何情况下自动重启
- --mode
- replicated:副本服务模式,在每个node上可以运行一个或多个副本
- global:全局服务模式,强制在每个node上都运行一个副本(例如收集所有容器的日志)
用docker-compose部署
docker-compose.yaml
version: '3.8' # Docker Compose 文件版本
services:
nginx: # 服务名称
image: nginx:latest # 使用的镜像
deploy: # 部署相关配置
replicas: 4 # 运行 4 个副本
placement: # 部署位置限制
constraints:
- node.role == worker # 只在工作节点部署
# - node.hostname == worker # 使用主机名指定用某台主机部署,此处113的名字就叫worker
update_config: # 更新策略
parallelism: 1 # 每次更新 1 个容器
delay: 10s # 每次更新间隔 10 秒
restart_policy: # 重启策略
condition: on-failure # 失败时重启
ports: # 端口映射
- "9999:80" # 主机端口:容器端口
volumes: # 数据卷挂载
- /home/testSwarm:/usr/share/nginx/html # 主机目录:容器目录
networks: # 网络配置
- nginx-net # 使用的网络名称
healthcheck: # 健康检查配置
test: ["CMD", "curl", "-f", "http://localhost"] # 检查命令
interval: 1m30s # 检查间隔
timeout: 10s # 超时时间
retries: 3 # 重试次数
start_period: 40s # 启动后等待时间
networks: # 网络定义
nginx-net: # 网络名称
driver: overlay # 使用 overlay 网络驱动部署
docker stack deploy -c docker-compose.yaml my-nginx关于update_config
完整的更新策略示例
deploy:
update_config:
parallelism: 1 # 每次更新一个容器
delay: 10s # 更新间隔
failure_action: pause # 失败时暂停更新
monitor: 30s # 监控更新状态的时间
max_failure_ratio: 0.3 # 最大失败率
order: start-first # 更新顺序不同设置示例
# 一次更新一个(最安全)
update_config:
parallelism: 1
delay: 10s
# 同时更新两个
update_config:
parallelism: 2
delay: 10s
# 同时更新所有(风险最大)
update_config:
parallelism: 0 # 0 表示同时更新所有使用场景
# 生产环境(谨慎更新)
deploy:
update_config:
parallelism: 1
delay: 30s
failure_action: pause
# 测试环境(快速更新)
deploy:
update_config:
parallelism: 2
delay: 5s
failure_action: continue在 docker-compose.yaml 中预先配置回滚策略
version: '3.8'
services:
nginx:
image: nginx:latest
deploy:
replicas: 5
update_config:
parallelism: 1
delay: 10s
failure_action: rollback # 失败时自动回滚
monitor: 30s
rollback_config: # 回滚配置
parallelism: 2
delay: 5s
failure_action: pause
monitor: 20s
order: stop-first测试副本挂掉
正常状态
手动删除一个管理节点的副本
手动删除一个工作节点的副本
如何保证数据一致性
上面的部署方式,每个节点都必须存在一个
/home/testSwarm目录,并且该目录下必须有index.html文件,如果在更新时更新漏了,就会导致数据不一致的问题
解决方法
- 使用网络文件系统(NFS)
- 使用分布式存储系统
- GlusterFS
- Ceph
- MinIO
- AWS EFS(如果在云环境)
- 使用 Docker Volume 插件
- 使用云存储解决方案
使用 NFS(网络文件系统)
# 1. 在管理节点(10.2.7.56)设置 NFS 服务器
yum install -y nfs-utils
mkdir -p /shared/data
chmod -R 755 /shared/data
# 配置 NFS 导出
echo "/shared/data 10.2.7.0/24(rw,sync,no_root_squash)" >> /etc/exports
exportfs -r
systemctl enable --now nfs-server
# 2. 在工作节点(10.2.7.113)挂载
yum install -y nfs-utils
mkdir -p /shared/data
mount -t nfs 10.2.7.56:/shared/data /shared/data
# 3. 修改 service 配置使用共享目录
docker service create \
--name nginx \
--replicas 4 \
--mount type=bind,source=/shared/data,target=/usr/share/nginx/html \
-p 9999:80 \
nginx使用 Docker Volume 插件
# 例如使用 NFS Volume Plugin
docker plugin install trajano/docker-volume-nfs
# 创建卷
docker volume create -d trajano/docker-volume-nfs \
--opt device=10.2.7.56:/shared/data \
shared-data
# 使用卷创建服务
docker service create \
--name nginx \
--replicas 4 \
--mount type=volume,source=shared-data,target=/usr/share/nginx/html \
-p 9999:80 \
nginx集群容器互联
注意
该部分用于测试如果不使用docker service该如何让容器之间通过容器名进行网络互联
创建用于集群的网络
在主节点上创建网络
docker network create --driver overlay --attachable ollama-network- --driver overlay - 指定网络驱动类型为 "overlay"(用于 Swarm 集群环境)
- --attachable - 这是一个重要的标志,允许独立的容器(非 swarm 服务)也能连接到这个网络
查看网络 坑点:在主节点上看可以看到创建的网络,但是在子节点上看时,需要创建完容器后才能看到
docker network ls测试容器互联链接
在56上部署ollama/ollama,在113上部署ghcr.io/open-webui/open-webui:latest
部署
ollama/ollama
docker run -d --name=ollama \
--network ollama-network \
--restart=always \
-p 32768:11434 \
-v /home/smisuser/data/:/root/.ollama \
ollama/ollama部署
ghcr.io/open-webui/open-webui:latest,OLLAMA_BASE_URL这个环境变量需要参考官方 官方文档)
docker run -d \
--name open-webui \
--network ollama-network \
--restart always \
-p 4000:8080 \
-e OLLAMA_BASE_URL=http://ollama:11434 \
-v open-webui:/app/backend/data \
ghcr.io/open-webui/open-webui:latest访问webui地址,查看是否能正确加载到模型,加载成功
http://10.2.7.113:4000docker退出集群
子节点退出集群
要退出集群,需要先在需要退出的子节点上退出,然后在在主节点上删除对应的子节点
docker swarm leave --force当前使用例子,先退出子节点,再退出主节点(是否加上
-force的执行结果如图所示)在主节点查看节点情况,会显示113这台主机的状态为down
主节点删除子节点
主节点需要手动删除该退出集群的节点
docker node rm 节点id或hostname
服务器中docker相关的修复项
docker服务文件目录(docker.service所在位置)
cd /usr/lib/systemd/system做完配置后需要重启docker
systemctl daemon-reload
systemctl restart docker限制容器间不受控的互相网络通信
注意
配置了限制容器间不受控的互相网络通信之后,如果容器不在同一个网络里,容器之间将无法互相访问 将容器链接网络的命令:docker network connect 网络名 容器名
修改docker.service,在ExecStart这行中加入
--icc=false
[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd --userland-proxy=false --userns-remap=defalut --icc=false -H fd:// --containerd=/run/containerd/containerd.sock
ExecReload=/bin/kill -s HUP $MAINPID
TimeoutStartSec=0
RestartSec=2
Restart=always禁用用户空间代理
同上,加入
--userland-proxy=false或者在daemon.json中加入"userland-proxy": false
验证配置
docker info | grep "Userland Proxy" # Userland Proxy: false作用
禁用用户空间代理(Userland Proxy)在 Docker 中的主要作用是提高网络性能和安全性。以下是禁用用户空间代理的一些主要用途和优点:
1. 提高网络性能:
- 减少延迟:用户空间代理会在 Docker 容器和宿主机之间引入额外的网络层,可能导致网络延迟。禁用用户空间代理可以直接使用 Linux 内核的网络堆栈,从而减少延迟。
- 提高吞吐量:通过直接使用内核网络堆栈,禁用用户空间代理可以提高网络吞吐量,尤其是在高负载的情况下。
2. 简化网络配置:
- 避免复杂性:用户空间代理会增加网络配置的复杂性,禁用它可以简化网络设置,减少潜在的配置错误。
3. 增强安全性:
- 减少攻击面:用户空间代理在网络层引入了额外的组件,可能成为攻击的目标。禁用它可以减少潜在的安全风险。
- 直接使用内核功能:通过直接使用内核的网络功能,可以减少中间层的安全隐患。
4. 兼容性:
- 与某些网络驱动程序兼容:某些网络驱动程序(如 macvlan 或 ipvlan)可能与用户空间代理不兼容。禁用用户空间代理可以确保这些驱动程序正常工作。
5. 适用于特定场景:
- 高性能应用:对于需要高性能网络的应用(如实时通信、视频流等),禁用用户空间代理可以提供更好的性能。
- 容器化微服务:在微服务架构中,禁用用户空间代理可以提高服务之间的通信效率。启用user namespace命名空间
同上,加入
--userns-remap=defalut或者在daemon.json中加入"userns-remap": "default"
验证配置
docker info | grep "Userns" #Userns: enabled作用:
用户命名空间(User Namespace)在 Docker 中的主要作用是增强容器的安全性和隔离性。以下是用户命名空间的一些关键用途和好处:
1. 增强安全性:
- 权限隔离:用户命名空间允许容器内的用户与宿主机上的用户进行隔离。即使容器内的用户具有特权(如 root 用户),在宿主机上也不会拥有相应的特权。这意味着即使容器被攻陷,攻击者也无法直接获得宿主机的 root 权限。
- 降低攻击面:通过将容器内的用户映射到宿主机上的非特权用户,减少了潜在的攻击面,降低了安全风险。
2. 资源限制:
- 用户命名空间可以帮助限制容器对宿主机资源的访问。例如,容器内的用户可能无法访问宿主机上的某些文件或设备,从而进一步增强安全性。
3. 更好的隔离:
- 用户命名空间提供了更好的隔离机制,使得不同容器之间的用户和组 ID 不会冲突。这对于运行多个容器的环境尤其重要,可以避免权限和访问问题。
4. 简化权限管理:
- 在某些情况下,用户命名空间可以简化权限管理。通过将容器内的用户映射到宿主机上的特定用户,可以更容易地管理文件和目录的权限。
5. 兼容性:
- 用户命名空间使得在容器中运行需要特权的应用程序(如数据库、Web 服务器等)变得更加安全,而不必担心它们会影响宿主机的安全性。
总结
用户命名空间在 Docker 中的主要作用是提供更强的安全性和隔离性,降低容器对宿主机的潜在风险。通过将容器内的用户与宿主机的用户进行隔离,用户命名空间可以有效地保护宿主机免受容器内潜在攻击的影响。将容器的根文件系统挂载为只读模式
docker run --read-only -it your_image挂载特定目录为可写 如果容器内的某些目录需要可写权限(例如,日志目录或临时文件目录),你可以使用 -v 选项将这些目录挂载为可写。例如:
docker run --read-only -v /path/to/writable/dir:/path/in/container -it your_imagedockercompose
version: '3.8'
services:
my_service:
image: your_image
read_only: true
volumes:
- /path/to/writable/dir:/path/in/container验证配置
进入容器并尝试修改文件系统来验证配置是否成功作用
将容器的根文件系统设置为只读模式具有多种安全性和管理上的好处,以下是一些主要用途和优点:
1. 增强安全性:
- 防止恶意修改:将根文件系统设为只读可以防止容器内的应用程序或攻击者对文件系统进行恶意修改。这在运行不可信或潜在有害的代码时尤其重要。
- 限制攻击面:即使容器被攻陷,攻击者也无法修改系统文件或配置,从而降低了对宿主机的潜在威胁。
2. 数据完整性:
- 保护关键文件:某些关键文件(如配置文件、二进制文件等)不应被修改。将根文件系统设为只读可以确保这些文件的完整性。
- 防止意外更改:在开发和测试环境中,防止开发人员或测试人员意外修改文件系统。
3. 简化故障排除:
- 一致性:只读模式可以确保容器在每次启动时都处于相同的状态,便于调试和故障排除。
- 可预测性:容器的行为更加可预测,因为文件系统不会在运行时发生变化。
4. 资源管理:
- 减少存储需求:只读文件系统可以减少对存储的需求,因为不需要频繁写入数据。
- 提高性能:在某些情况下,只读文件系统可以提高性能,因为系统不需要处理写入操作。
5. 适用于特定场景:
- 静态应用:对于一些静态应用(如 Web 服务器),只读模式是合适的,因为它们不需要修改文件系统。
- 临时容器:在某些临时或短期运行的容器中,使用只读模式可以确保容器在完成任务后不会留下任何持久的更改。
总结
将容器的根文件系统设置为只读模式可以显著增强安全性、保护数据完整性、简化故障排除,并提高资源管理效率。这种做法在运行不可信代码或需要高安全性的环境中尤其重要。设置on-failure重启策略并限制次数为5
docker run --restart on-failure:5 -it your_imageversion: '3.8'
services:
my_service:
image: your_image
restart: on-failure:5作用
设置 Docker 容器的重启策略为 on-failure 并限制重启次数为 5 次具有多种用途和好处,以下是一些主要的优点:
1. 提高容器的可靠性:
- 自动恢复:当容器因错误或故障而停止时,重启策略可以自动尝试重新启动容器。这有助于确保服务的持续可用性,尤其是在处理临时故障时。
2. 减少人工干预:
- 降低运维负担:通过自动重启失败的容器,运维人员不需要手动干预来恢复服务。这可以节省时间和精力,特别是在大规模部署中。
3. 控制重启次数:
- 防止无限重启:通过限制重启次数为 5 次,可以防止容器在持续失败的情况下无限重启。这有助于避免资源浪费和潜在的服务崩溃,确保系统的稳定性。
4. 适应性:
- 应对瞬时故障:在某些情况下,容器可能会因为瞬时故障(如网络问题、临时资源不足等)而停止。重启策略可以帮助容器在这些情况下自动恢复。
5. 监控和告警:
- 触发告警:如果容器在达到重启限制后仍然失败,可以设置监控和告警机制,通知运维人员进行进一步的调查和处理。这有助于及时发现和解决潜在问题。
6. 适用于微服务架构:
- 服务可用性:在微服务架构中,服务之间的依赖关系可能会导致某个服务的失败影响到其他服务。通过设置重启策略,可以提高整个系统的可用性和稳定性。
总结
设置 on-failure 重启策略并限制重启次数为 5 次可以显著提高容器的可靠性,减少人工干预,控制资源使用,并适应瞬时故障。这种配置在生产环境中尤其重要,有助于确保服务的持续可用性和系统的稳定性。不要共享主机进程命名空间
docker run --pid=private -it your_imageversion: '3.8'
services:
my_service:
image: your_image
pid: "container:other_container_id" # 共享另一个容器的进程命名空间查看容器的进程命名空间设置
docker inspect <container_id> --format '{{.HostConfig.PidMode}}'作用
在 Docker 中,进程命名空间的设置(如 private、host 和 container:<container_id>)具有不同的作用和用途。以下是每种设置的详细作用:
1. private
- 作用:
- 进程隔离:容器使用自己的进程命名空间,容器内的进程只能看到该容器内的进程,无法访问宿主机或其他容器的进程。
- 安全性:增强了容器的安全性,防止容器内的进程干扰宿主机或其他容器的进程。
- 适用场景:适用于大多数应用场景,尤其是需要高安全性和隔离性的环境。
2. host
- 作用:
- 共享进程视图:容器共享宿主机的进程命名空间,容器内的进程可以看到宿主机上的所有进程。
- 调试和监控:适用于需要与宿主机进程交互的场景,例如调试工具、监控工具或需要访问宿主机服务的应用。
- 性能:在某些情况下,使用宿主机的进程命名空间可以提高性能,因为减少了进程间的隔离开销。
3. container:<container_id>
- 作用:
- 共享进程信息:容器共享另一个容器的进程命名空间,容器内的进程可以访问共享容器的进程信息。
- 紧密协作:适用于需要紧密协作的多个容器,例如在同一进程空间中运行的服务,允许它们相互访问进程信息。
- 资源管理:可以更好地管理资源,特别是在需要多个服务协同工作的场景中。
总结
- private:提供良好的隔离性和安全性,适用于大多数场景。
- host:适用于需要与宿主机进程交互的场景,提供更高的性能和可访问性。
- container:<container_id>:适用于需要共享进程信息的容器,允许它们紧密协作。
选择合适的进程命名空间设置取决于应用的需求、安全考虑和性能要求。不要共享主机的ipc命名空间
docker run --ipc=private -it your_image```yaml
version: '3.8'
services:
my_service:
image: your_image
ipc: "private" # 确保不共享宿主机的 IPC 命名空间查看容器的 IPC 命名空间设置
docker inspect <container_id> --format '{{.HostConfig.IpcMode}}'作用
不共享主机的 IPC(Inter-Process Communication)命名空间具有多种重要作用和好处,以下是主要的作用:
1. 增强安全性
- 隔离性:通过不共享 IPC 命名空间,容器内的进程无法访问宿主机或其他容器的 IPC 资源(如共享内存、信号量等)。这减少了潜在的攻击面,防止恶意进程通过 IPC 进行攻击或数据窃取。
- 防止信息泄露:容器内的进程无法访问宿主机或其他容器的进程间通信,这有助于保护敏感数据和信息,确保数据的隐私性。
2. 提高稳定性
- 避免干扰:如果容器共享 IPC 命名空间,容器内的进程可能会干扰宿主机或其他容器的进程间通信,导致不稳定或不可预测的行为。通过使用独立的 IPC 命名空间,可以避免这种干扰。
- 独立性:每个容器都可以独立运行,确保其进程间通信不会受到其他容器或宿主机进程的影响。
3. 适用于多租户环境
- 资源隔离:在多租户环境中,确保不同用户或服务之间的 IPC 资源隔离是至关重要的。通过不共享 IPC 命名空间,可以确保不同租户之间的资源不会相互干扰,增强了安全性和稳定性。
4. 简化故障排除
- 可预测性:使用独立的 IPC 命名空间可以使容器的行为更加可预测,便于调试和故障排除。开发人员可以更容易地识别和解决问题,而不必担心其他容器的影响。
5. 适用于特定应用场景
- 容器化微服务:在微服务架构中,服务之间的通信通常通过网络进行,而不是通过 IPC。使用独立的 IPC 命名空间可以确保服务之间的通信不会受到影响,增强了系统的可用性和稳定性。
总结
不共享主机的 IPC 命名空间可以显著增强容器的安全性、稳定性和隔离性,防止进程间的干扰和信息泄露。这在需要高安全性和隔离性的应用场景中尤其重要。不要共享主机的UTS命名空间
docker run --uts=private -it your_imageversion: '3.8'
services:
my_service:
image: your_image
uts: "private" # 确保不共享宿主机的 UTS 命名空间在dockercompose中加上
uts: "private",或者在docker运行容器时加上--uts=private
查看容器的UTS命名空间设置
docker inspect <container_id> --format '{{.HostConfig.UTSMode}}'作用
不共享主机的 UTS(UNIX Time-Sharing)命名空间的主要作用包括以下几个方面:
1. 增强安全性
- 隔离性:通过不共享 UTS 命名空间,容器内的进程无法访问宿主机或其他容器的主机名和域名。这种隔离减少了潜在的攻击面,防止恶意进程通过获取主机名或域名信息进行攻击。
- 防止信息泄露:容器内的进程无法获取宿主机的主机名和域名信息,从而保护敏感数据,确保数据的隐私性。
2. 提高稳定性
- 避免干扰:如果容器共享 UTS 命名空间,容器内的进程可能会干扰宿主机或其他容器的主机名设置,导致不稳定或不可预测的行为。使用独立的 UTS 命名空间可以避免这种干扰,确保每个容器的主机名设置不会影响其他容器或宿主机。
- 独立性:每个容器都可以独立运行,确保其主机名和域名设置不会受到其他容器或宿主机进程的影响。
3. 适用于多租户环境
- 资源隔离:在多租户环境中,确保不同用户或服务之间的 UTS 资源隔离是至关重要的。通过不共享 UTS 命名空间,可以确保不同租户之间的资源不会相互干扰,增强了安全性和稳定性。
4. 简化故障排除
- 可预测性:使用独立的 UTS 命名空间可以使容器的行为更加可预测,便于调试和故障排除。开发人员可以更容易地识别和解决问题,而不必担心其他容器的影响。
5. 适用于特定应用场景
- 容器化微服务:在微服务架构中,服务之间的通信通常通过网络进行,而不是通过 UTS。使用独立的 UTS 命名空间可以确保服务之间的通信不会受到影响,增强了系统的可用性和稳定性。
总结
不共享主机的 UTS 命名空间可以显著增强容器的安全性、稳定性和隔离性,防止进程间的干扰和信息泄露。这在需要高安全性和隔离性的应用场景中尤其重要。通过确保每个容器都有自己的主机名和域名设置,可以提高系统的整体安全性和可靠性。不要共享主机的user命名空间
docker run --userns=private -it your_imageversion: '3.8'
services:
my_service:
image: your_image
userns: "private" # 确保不共享宿主机的用户命名空间查看容器的 user 命名空间设置
docker inspect <container_id> --format '{{.HostConfig.UsernsMode}}'作用
不共享主机的用户命名空间(User Namespace)在 Docker 中的主要作用包括以下几个方面:
1. 增强安全性
- 权限隔离:通过不共享用户命名空间,容器内的用户(即使是 root 用户)不会拥有宿主机上的相应权限。这意味着即使容器被攻陷,攻击者也无法直接获得宿主机的 root 权限,从而降低了安全风险。
- 防止权限提升:容器内的用户无法访问宿主机的用户和组信息,减少了通过权限提升攻击获取宿主机资源的可能性。
2. 提高稳定性
- 避免干扰:如果容器共享用户命名空间,容器内的用户可能会干扰宿主机或其他容器的用户和组设置,导致不稳定或不可预测的行为。使用独立的用户命名空间可以避免这种干扰,确保每个容器的用户设置不会影响其他容器或宿主机。
- 独立性:每个容器都可以独立运行,确保其用户和组设置不会受到其他容器或宿主机进程的影响。
3. 适用于多租户环境
- 资源隔离:在多租户环境中,确保不同用户或服务之间的用户资源隔离是至关重要的。通过不共享用户命名空间,可以确保不同租户之间的资源不会相互干扰,增强了安全性和稳定性。
4. 简化故障排除
- 可预测性:使用独立的用户命名空间可以使容器的行为更加可预测,便于调试和故障排除。开发人员可以更容易地识别和解决问题,而不必担心其他容器的影响。
5. 适用于特定应用场景
- 容器化微服务:在微服务架构中,服务之间的通信通常通过网络进行,而不是通过用户命名空间。使用独立的用户命名空间可以确保服务之间的通信不会受到影响,增强了系统的可用性和稳定性。
总结
不共享主机的用户命名空间可以显著增强容器的安全性、稳定性和隔离性,防止进程间的干扰和信息泄露。这在需要高安全性和隔离性的应用场景中尤其重要。通过确保每个容器都有自己的用户和组设置,可以提高系统的整体安全性和可靠性。限制容器的内存使用
docker run --memory="512m" -it your_image
docker run --memory="1g" -it your_image- m:表示兆字节(MB)。
- g:表示千兆字节(GB)。
- k:表示千字节(KB)。
version: '3.8'
services:
my_service:
image: your_image
deploy:
resources:
limits:
memory: 512M # 限制内存为 512MB验证内存限制
docker inspect <container_id> --format '{{.HostConfig.Memory}}'注意事项
- 内存限制:如果容器使用的内存超过限制,Docker 将会终止该容器。
- 交换空间:还可以使用 --memory-swap 选项来设置容器的交换空间限制。交换空间是物理内存不足时使用的虚拟内存。例如,设置内存限制为 512MB,交换空间限制为 1GB:
docker run --memory="512m" --memory-swap="1g" -it your_image作用
限制 Docker 容器的内存使用具有多种重要作用和好处,以下是主要的作用:
1. 防止资源耗尽
- 保护宿主机:通过限制容器的内存使用,可以防止单个容器消耗过多的内存资源,从而影响宿主机和其他容器的性能。这有助于确保系统的稳定性和可用性。
- 避免 OOM(Out of Memory)杀死:如果容器使用的内存超过宿主机的可用内存,操作系统可能会启动 OOM 杀手来终止进程。通过设置内存限制,可以减少这种情况的发生。
2. 提高性能
- 资源分配:限制内存使用可以确保容器在可控的资源范围内运行,从而提高应用程序的性能。容器在内存限制内运行时,能够更有效地利用可用资源。
- 减少交换:通过限制内存使用,可以减少容器使用交换空间的可能性,从而提高性能。过多的交换会导致性能下降,因为访问磁盘比访问内存慢得多。
3. 增强安全性
- 隔离性:限制容器的内存使用可以增强容器之间的隔离性,防止某个容器的内存使用影响到其他容器或宿主机。这在多租户环境中尤为重要。
- 防止恶意行为:如果容器内的应用程序被攻击或出现故障,限制内存使用可以防止其消耗过多资源,降低潜在的安全风险。
4. 适用于微服务架构
- 资源管理:在微服务架构中,多个服务可能在同一宿主机上运行。通过限制每个容器的内存使用,可以更好地管理资源,确保每个服务都有足够的资源运行。
- 可预测性:设置内存限制可以使容器的行为更加可预测,便于监控和管理。
5. 简化故障排除
- 可控性:通过限制内存使用,可以更容易地识别和解决内存相关的问题。开发人员可以根据内存使用情况进行调试和优化。
总结
限制 Docker 容器的内存使用可以有效地防止资源耗尽、提高性能、增强安全性,并适用于微服务架构。这种做法在生产环境中尤其重要,有助于确保系统的稳定性和可靠性。通过合理设置内存限制,可以更好地管理和优化容器化应用程序的资源使用。


注意:如果需要加入节点的机器上有多张网卡,需要用
113升级为管理节点后 



在
此时在
手动删除一个管理节点的副本
手动删除一个工作节点的副本 
在主节点查看节点情况,会显示113这台主机的状态为down 