Skip to content

Docker笔记

podman笔记

打开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 dockerlinux系统中查看docker位置

集群常用

构建集群案例速查

集群管理常用命令速查

指定用于集群的网络驱动overlay(用于 Swarm 集群环境)

sh
-driver overlay

允许独立的容器(非 swarm 服务)也能连接到这个网络,这是一个重要的标志,需要在使用集群时使用该参数

sh
--attachable

单机常用

检查容器健康状态

sh
docker inspect --format='{{.State.Health.Status}}' 容器名

linux中起别名

sh
alias dps='docker ps --format "table {{.ID}}\t{{.Image}}\t{{.Ports}}\t{{.Status}}\t{{.Names}}"'

限制内存大小

sh
 --memory="1g" --memory-swap="1g"

限制cpu核心数

sh
--cpus="1"

自动启动

sh
--restart=always

运行完成后自动销毁容器

sh
 --rm

常用镜像挂载速查

部署mysql

sh
# 最后一个斜杠是换行
# 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

sh
# --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-slim

custom.env中的内容

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

sh
docker run -d --name nginx -p 80:80 -v html:/usr/share/nginx/html nginx

部署rabbitmq

注意:如果需要管理端,则需要拉取后面带management标签的镜像,例如rabbitmq:management 否则需要执行下面的步骤自行开启网页端管理界面

sh
docker run -d --name rabbit -p 15672:15672 -p 5672:5672 rabbitmq

进入容器

sh
docker exec -it rabbitmq bash

开启网页端管理界面

java
rabbitmq-plugins enable rabbitmq_management

开防火墙端口

5672:java端访问的端口
15672:前端的端口:

部署redis

sh
docker run --name redis -d -p 6379:6379 redis

部署seata

sh
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,自己改一下

不需要配置文件

sh
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容器,然后将生成的配置文件复制到主机数据卷的位置,然后再正式启动

sh
# 复制配置文件
docker run --name temp-tomcat tomcat
# 停止容器运行
ctrl+c
# 复制文件到数据卷
docker cp temp-tomcat:/usr/local/tomcat/conf /usr/tomcat
# 删除临时容器
docker rm -f temp-tomcat

正式运行

sh
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)

sh
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)

sh
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"

测试服务器上的老版本

sh
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"

本地测试新老版本

sh
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

sh
docker pull minio/mc

使用mc迁移数据

部署opengauss

单机模式

如果是windows端,请使用这个enmotech/opengauss-lite:latest镜像

sh
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的镜像)
sh
docker pull enmotech/opengauss:5.0.1
复制粘贴脚本主从部署

官方(没有指定数据卷) enmotech/opengauss - Docker Image | Docker Hub

sh
wget https://raw.githubusercontent.com/enmotech/enmotech-docker-opengauss/master/create_master_slave.sh

我的(补充了数据卷)

create_master_slave.sh

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

用命令备份
sh
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

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 "***备份脚本执行完毕***"

执行脚本

sh
chmod +x backup_opengauss.sh
./backup_opengauss.sh

部署elasticsearch

方法一:docker直接跑

根据当前服务器情况修改ES_JAVA_OPTS环境变量 访问服务器对应的9200端口即可

sh
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

安装中文分词器插件

进入容器

sh
docker exec -it elasticsearch bash
安装插件的方式
联网安装

联网安装插件(这是官方ceo仓库的路径)

sh
elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.17.6/elasticsearch-analysis-ik-7.17.6.zip

联网安装插件(这是官方仓库的路径)

sh
elasticsearch-plugin install https://github.com/infinilabs/analysis-ik/releases/download/v7.17.6/elasticsearch-analysis-ik-7.17.6.zip
本地zip安装

本地安装zip插件

sh
elasticsearch-plugin install file:///usr/share/elasticsearch/plugins/elasticsearch-analysis-ik-7.17.6.zip
查看已安装的插件

命令查看

sh
elasticsearch-plugin list

api查看

http://localhost:9200/_cat/plugins

exit退出容器后重启容器

sh
docker restart elasticsearch

方法二:dockercompose

先下载好分词器插件的zip包,地址如下

sh
https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v7.17.6/elasticsearch-analysis-ik-7.17.6.zip

dockerfile

dockerfile
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.zip

dockercompose

yaml
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。

sh
docker run --name kibana -p 5601:5601 --link elasticsearch:es  -e "elasticsearch.hosts=http://es:9200"  -d kibana:7.17.6

部署jenkins

最新版

sh
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

查看密码

sh
cat /data/jenkins_home/secrets/initialAdminPassword

优化版

sh
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

项目接入prometheus案例

dockercompose

yml
# 这个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)

sh
sudo chown -R 65534:65534 /home/docker_volums/prometheus_volumes
sudo chmod -R 755 /home/docker_volums/prometheus_volumes

设置 Grafana 目录权限 (Grafana 使用 uid=472)

sh
sudo chown -R 472:472 /home/docker_volums/grafana_volumes
sudo chmod -R 755 /home/docker_volums/grafana_volumes

部署wireguard

wg-easy官方文档

需要将10.2.7.56替换为你的ip或域名;将'<🚨YOUR_ADMIN_PASSWORD_HASH>'替换为你生成的密码

sh
# 生成你的密码($需要双写转义)
docker run --rm -it ghcr.io/wg-easy/wg-easy wgpw 'YOUR_PASSWORD'
# 例如生成PASSWORD_HASH='$$2b$$12$$coPqCsPtcFO.Ab99xylBNOW4.Iu7OOA2/ZIboHN6/oyxca3MWo7fW' // literally YOUR_PASSWORD
yml
services:
  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
yml
# 如果需要让用户可以访问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:80
sh
docker 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

sh
docker run -id --name=ollama -p 11434:11434 -v F:\ollama_data:/root/.ollama ollama/ollama
yml
services:  
  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: ollama
yml
services:  
  # 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文件夹

新的开源项目

sh
docker run --restart=always -id -p 12345:12345 --name jrebel-license-active-server yuxiaoyao520/jrebel-license-active-server:latest

使用(服务器地址和邮箱)

txt
https://127.0.0.1:123456/ec190ca9-e7b1-4a8c-ad0a-4267c82a0a11
123456789@qq.com

老项目(现在用不了了,但是纪念一下)

sh
docker run --restart=always -dit --name=jreber -p 8888:8888 qierkang/golang-reverseproxy

防火墙命令速查

防火墙命令

常用dockerfile写法

Dockerfile 手册

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检查

dockerfile
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

dockerfile
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写法

docker-compose手册

使用include将通用的docker-compose文件引入进来

docker-compose

yaml
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: true

docker-compose-base

yaml
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

常用排错方法

容器起不来

查看容器日志

sh
docker logs 容器名

项目中看不到图片

docker查看镜像详细信息,查看镜像的基本版本是否兼容

sh
docker inspect 镜像名称

安装docker

升级docker重新再执行一遍卸载和安装

官方安装方式,使用dnf安装docker

官方文档,有对应linux发行版的安装方式

卸载老版本docker

如果没有dnf,请先安装dnf

sh
sudo dnf remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

设置docker仓库

sh
sudo dnf -y install dnf-plugins-core
sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo

安装Docker Engine

sh
sudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sh
# 查看可以安装的版本,会列出可以安装的版本,例如: 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是否安装成功

sh
sudo docker run hello-world

使用yum的安装方式

sh
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

sh
bash <(curl -sSL https://linuxmirrors.cn/docker.sh)

docker加上代理

json
  "proxies": {
    "http-proxy": "http://127.0.0.1:10809",
    "https-proxy": "http://127.0.0.1:10809"
  }

如果加上代理之后还是拉不下来,就多重试几次

镜像加速

有代理就不需要这个registry-mirrors配置了

shell
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

候选源

text
"https://docker.1panel.live"

镜像源地址延迟测试

https://www.itdog.cn/ping

官方镜像仓库

http
hub.docker.com

docker修改数据存储目录

查看docker当前数据目录位置

sh
docker info --format '{{.DockerRootDir}}'

停止docker

sh
sudo systemctl stop docker

编辑daemon.json文件

sh
vim /etc/docker/daemon.json

加上指定位置的配置

json
{
    "registry-mirrors": ["https://docker.1ms.run"],
    "data-root": "/home/docker"
}

将默认目录的文件拷贝到目标目录,docker默认不会迁移容器

sh
cp -r /var/lib/docker /home/

启动docker

sh
sudo systemctl start docker

完全卸载 Docker

方法一

sh
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相关的软件包

sh
yum list installed | grep docker

例如执行上述语句后的结果

text
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

如果结果和上面的一样,可以执行下述语句

sh
sudo yum remove docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-runc

方法三

找到docker

sh
which docker
docker --version

删除所有 Docker 相关文件和目录

sh
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
sudo rm -rf /usr/bin/docker
sudo rm -rf /etc/docker

帮助

shell
# 直接敲
docker
# 或者用下面这个
docker 命令 --help

Docker 进程相关命令

shell
# 启动docker服务:
systemctl start docker 
# 停止docker服务:
systemctl stop docker 
# 重启docker服务:
systemctl restart docker
# 查看docker服务状态:
systemctl status docker 
# 设置开机启动docker服务:
systemctl enable docker

Docker 镜像相关命令

shell
# 查看镜像: 查看本地所有的镜像
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.0

Docker 容器相关命令

查看容器

shell
# 查看正在运行的容器
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}}"

创建并启动容器

shell
# 基本格式
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为创建的容器命名。

容器操作

启动容器

shell
docker start 容器名称或ID

停止容器

shell
docker stop 容器名称或ID

删除容器

shell
# 单个删除(如果容器是运行状态则删除失败,需要停止容器才能删除)
docker rm 容器名称(或ID)
# 强制删除
docker rm -f 容器名称(或ID)
# 强制删除所有容器
docker rm -f ${docker ps -a -q}
# 一次删除多个容器实例(建议别用)
docker ps -a -q|xargs docker rm

进入容器

shell
# 进入容器(用这种方式进入容器,在退出容器后,容器不会关闭)
docker exec 参数 容器名 进入容器后的操作
## 例如(mysql -uroot -p表示进到mysql容器后执行的命令)
docker exec -it mysql mysql -uroot -p
## 例如(/bin/bash表示进到nginx容器后执行的命令)
docker exec -it nginx /bin/bash

退出容器

shell
# run进容器,用该命令退出容器后,容器停止
# exec进容器,不会停止
exit
# run进容器,用该命令退出容器后,容器不停止
ctrl+p+q

查看容器信息

shell
docker inspect 容器名称或ID

查看对应容器日志

shell
docker logs -f 容器名
# 例如
docker logs -f nacos

Docker 容器的数据卷

理解

基本命令
shell
# 创建数据卷
docker volume create 
# 查看所有数据卷
docker volume ls
# 删除指定数据卷
docker volume rm
# 查看某个数据卷详情
docker volume inspect
# 清除数据卷
docker volume prune
运行时创建
shell
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挂载到主机上

shell
# 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/bash

dockerfile

介绍

由于制作镜像的过程中,需要逐层处理和打包,比较复杂,所以Docker就提供了自动打包镜像的功能。我们只需要将打包的过程,每一层要做的事情用固定的语法写下来,交给Docker去执行即可。而这种记录镜像结构的文件就称为Dockerfile

http
https://docs.docker.com/engine/reference/builder/

指令

使用

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

例子

网络

介绍

容器的网络IP其实是一个虚拟的IP,其值并不固定与某一个容器绑定,如果我们在开发时写死某个IP,而在部署时很可能MySQL容器的IP会发生变化,连接会失败。

http
https://docs.docker.com/engine/reference/commandline/network/

为什么要用网络

在docker的默认网络中,容器一被启动,就会按顺序被分配一个网络,如果这次启动mysql时分配的是172.17.0.3,下次如果redis先启动,则可能会把改地址占用了,要解决由于自动分配网络导致连接失败的问题,可以使用docker中的network功能,只要将容器加到自己分配的网络中, 那么我们就可以直接用容器别名来访问该容器,这就解决了我们要使用ip来访问该容器的问题

在自定义网络中,可以给容器起多个别名,默认的别名是容器名本身 在同一个自定义网络中的容器,可以通过别名互相访问

命令

shell
# 创建一个网络
docker network create
# 查看所有网络
docker network ls
# 删除指定网络
docker network rm
# 清除未使用的网络
docker network prune
# 使指定容器连接加入某网络
docker network connect
# 使指定容器连接离开某网络
docker network disconnect
# 查看网络详细信息
docker network inspect

例子

shell
# 在运行时加入网络(这样创建,不会加入默认网络,只会加入指定网络)
# 要先创建这个网络!!!
docker -run -d --name 容器别名 -p 8080:8080 --network 网络名称 容器名称

项目部署案例(将相关文件移动到/root下)

http
# 项目参考链接
https://b11et3un53m.feishu.cn/wiki/MWQIw4Zvhil0I5ktPHwcoqZdnec

部署后端

SpringBoot配置文件()

在容器里使用则配置为容器名

用maven打包项目(选择package)

编写dockerfile

shell
# 基础镜像
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创建网络

shell
docker network create hm-net

docker运行mysql

shell
# 有配置文件,就先把配置文件先移动到数据卷里面,然后再构建
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项目镜像并运行

shell
# 打包镜像
docker build -t hmall .
# 运行镜像
docker run -d --name hm -p 8080:8080 --network hm-net hmall

打开linux的防火墙对应端口,然后访问hi接口

部署前端

部署nginx

shell
# 将配置文件和前端打包好的文件粘贴到数据卷对应位置
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 \
    nginx

DockerCompose

介绍

Docker Compose通过一个单独的docker-compose.yml 模板文件(YAML 格式)来定义一组相关联的应用容器,帮助我们实现多个相互关联的Docker容器的快速部署。

docker和docker compose语法对比

命令

类型参数或指令说明
Options-f指定compose文件的路径和名称
-p指定project名称。project就是当前compose文件中设置的多个service的集合,是逻辑概念
Commandsup创建并启动所有service容器
down停止并移除所有容器、网络
ps列出所有启动的容器
logs查看指定容器的日志
stop停止容器
start启动容器
restart重启容器
top查看运行的进程
exec在指定的运行中容器中执行命令

案例(Redis主从同步集群)

shell
#自定义网络
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)

命令启动
shell
#创建网络
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:latest
docker-compose启动
yaml
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文件内容
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文件内容
yml
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相关命令
shell
# 启动所有容器
docker compose up -d

# 停止并删除所有容器
docker compose down

-d表示后台运行

测试

开启防火墙的18080端口,然后访问登录界面

text
账号:jack
密码:123

成功登录

假设已经使用dockercompose启动了所有容器,但是要重新部署hmall
sh
# 停止 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容器
sh
# 启动 `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 mysql

docker集群

docker swarm官方文档

实验环境

  • 我现在有两台物理机(内网ip分别为:10.2.7.5610.2.7.113),由于子网掩码为24,现在以56113代表这两台主机,方便区分
  • 其中56为管理节点,113为工作节点,并且两个主机都是单网卡

注意事项

需要确保两台机器的以下端口是开放的,开放端口的的方式,开放端口后还不生效,请重启一下试试

  • TCP 2377 - 集群管理通信
  • TCP/UDP 7946 - 节点间通信
  • UDP 4789 - overlay网络流量

修改各主机的主机名

建议这样做,方便后续管理

sh
# 56 
hostnamectl set-hostname master
# 113
hostnamectl set-hostname worker

初始化集群

注意

初始化之后,会生成加入工作节点的命令,以及如何生成加入管理节点的命令

56上初始化集群

sh
docker swarm init --advertise-addr 10.2.7.56

上述命令执行完成之后会生成一个用于加入56创建的集群的语句,执行结果如图所示

113作为工作节点加入集群

复制上面生成的命令,并在113上执行,会以工作节点的形式加入集群

sh
docker swarm join --token SWMTKN-1-2ccybp5pdtxg8g81i3uenj301vutdka4gf37efisf38thz2ohu-5qlfm6hyr8luujn4omb05hhga 10.2.7.56:2377

执行结果如图所示 注意:如果需要加入节点的机器上有多张网卡,需要用--advertise-addr参数指定网卡的ip作为广播地址,例如我的机器b就指定使用ip为10.2.7.113的网卡作为广播地址

sh
docker swarm join --advertise-addr 10.2.7.113 --token SWMTKN-1-2ccybp5pdtxg8g81i3uenj301vutdka4gf37efisf38thz2ohu-5qlfm6hyr8luujn4omb05hhga 10.2.7.56:2377

113作为管理节点加入集群

在加入工作节点的下方会生成如何生成加入管理节点的命令(图中黄色那条的命令)

sh
docker swarm join-token manager

复制上面生成的命令,并在113上执行,会以管理节点的形式加入集群

sh
docker swarm join --advertise-addr 10.2.7.113 --token SWMTKN-1-22ke9z1x10kll41u72n49humagrgwwi4gha2yc6l14lc6li5v2-5wd0wrmxqbvdygufm4ujvrgkm 10.2.7.56:2377

查看集群信息

在管理节点(此处为56)才可查看,结果如下图

sh
docker node ls

只有有管理权限的子节点才能看,如果在子节点113执行,执行结果如下, 113升级为管理节点后

集群管理常用命令

节点管理

docker node官方文档

查看节点
sh
docker node ls

查看某个节点情况
sh
docker node ps 节点的id或hostname

状态说明
active正常接受和运行任务、可以部署新的服务、默认的工作状态
drain停止接受新任务,现有任务会被转移到其他节点(主要用于:维护节点、升级系统、下线节点)
pause停止接受新任务、现有任务继续运行(适用于:临时停止调度、不想接收新任务但也不想迁移现有任务)
将节点升级为管理节点
sh
docker node promote 对应服务器的节点id或hostname
将节点降级为管理节点
sh
docker node demote 对应服务器的节点id或hostname
节点下线
sh
docker node update --availability drain 对应服务器的节点id或hostname

节点上线
sh
docker node update --availability drain 对应服务器的节点id或hostname

服务管理

docker service官方文档

通过命令创建服务

用法

sh
docker service create

部署nginx案例

部署visualizer案例

visualizer可以让swarm的服务滚动更新实时显示在UI界面上,便于观察滚动更新过程

sh
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的下一级

部署

docker stack官方文档

sh
# 部署 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.
指定机器部署

部署命令不变

sh
docker stack deploy -c docker-compose.yaml my-nginx

方法一,给节点添加标签,选择带有该标签的机器部署 注意:Docker Swarm 节点标签可以分为内置标签和自定义标签!!!

sh
# 加标签,标签名为deploy,标签值为worker1,这里的worker是指节点的hostname,113的hostname就是叫worker
docker node update --label-add deploy=worker1 worker
# 查看节点标签
docker node inspect worker
yml
services:
  nginx:
    image: nginx:latest
    deploy:
      replicas: 4
      placement:
        constraints:
          - node.labels.deploy == worker1    # 使用标签约束

内置标签(可以直接用)

yml
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        # 自定义标签

常用自定义标签

text
# 环境标签
- 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     # 数据库服务

方法二,使用主机名约束

yml
services:
  nginx:
    image: nginx:latest
    deploy:
      replicas: 4
      placement:
        constraints:
          - node.hostname == worker    # 使用主机名约束

更复杂的约束方式 constraints指硬性约束条件,强制要求部署在主机名为 worker 的节点上 preferences指软性偏好设置,尽量将容器分散在不同 zone 标签的节点上

yml
services:
  nginx:
    image: nginx:latest
    deploy:
      replicas: 4
      placement:
        constraints:
          - node.hostname == worker
        preferences:
          - spread: node.labels.zone
text
# 举例说明
# 如果有多个节点带有不同的 zone 标签:
Node1: zone=zone1
Node2: zone=zone2
Node3: zone=zone3

# 当部署多个副本时,会尽量均匀分布:
Replica1 -> zone1
Replica2 -> zone2
Replica3 -> zone3

使用多个约束条件

yml
services:
  nginx:
    image: nginx:latest
    deploy:
      replicas: 4
      placement:
        constraints:
          - node.hostname == worker
          - node.labels.deploy == worker1
          - node.role == worker
更新

语法

sh
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个副本)

sh
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上看容器状态

停止更新

立即停止正在进行的更新

sh
# 暂停更新
docker service update --update-pause nginx

# 或者对于 stack
docker service update --update-pause my-nginx_nginx
回滚

回滚到之前的版本

sh
# 回滚服务
docker service update --rollback nginx

# 对于 stack 服务
docker service update --rollback my-nginx_nginx

# 查看回滚状态
docker service ps nginx

使用具体版本回滚

sh
# 回滚到特定镜像版本
docker service update --image nginx:1.22 nginx

# 强制立即更新所有任务
docker service update --force nginx
监控和验证
sh
# 查看服务状态
docker service ps nginx

# 查看服务日志
docker service logs nginx

# 查看更新历史
docker service inspect nginx --pretty
查看已部署的服务
sh
docker service ls

查看对应服务信息
sh
docker service ps 服务名

查看服务日志
sh
# 在这句后面按下tab可以看到对应的提示docker service logs
# 查看服务日志
docker service logs 服务名
# 查看服务中某个容器日志
docker service logs 容器id

修改服务副本数量

使用scale

sh
# 将副本数改为 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

sh
# 更新副本数为 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创建为例)

sh
mkdir /home/testSwarm

将页面目录拷贝到其他机器(将113的拷贝到56

sh
scp -r /home/testSwarm/ root@10.2.7.56:/home/testSwarm

写一个页面

sh
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,它会把这个请求转发到集群内部有这个服务的节点上

通过命令部署

sh
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

yml
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 网络驱动

部署

sh
docker stack deploy -c docker-compose.yaml my-nginx
关于update_config

完整的更新策略示例

yml
deploy:
  update_config:
    parallelism: 1           # 每次更新一个容器
    delay: 10s               # 更新间隔
    failure_action: pause    # 失败时暂停更新
    monitor: 30s             # 监控更新状态的时间
    max_failure_ratio: 0.3   # 最大失败率
    order: start-first       # 更新顺序

不同设置示例

yml
# 一次更新一个(最安全)
update_config:
  parallelism: 1
  delay: 10s

# 同时更新两个
update_config:
  parallelism: 2
  delay: 10s

# 同时更新所有(风险最大)
update_config:
  parallelism: 0    # 0 表示同时更新所有

使用场景

yml
# 生产环境(谨慎更新)
deploy:
  update_config:
    parallelism: 1
    delay: 30s
    failure_action: pause

# 测试环境(快速更新)
deploy:
  update_config:
    parallelism: 2
    delay: 5s
    failure_action: continue

在 docker-compose.yaml 中预先配置回滚策略

yml
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(网络文件系统)
sh
# 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 插件
sh
# 例如使用 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该如何让容器之间通过容器名进行网络互联

创建用于集群的网络

在主节点上创建网络

sh
docker network create --driver overlay --attachable ollama-network
  • --driver overlay - 指定网络驱动类型为 "overlay"(用于 Swarm 集群环境)
  • --attachable - 这是一个重要的标志,允许独立的容器(非 swarm 服务)也能连接到这个网络

查看网络 坑点:在主节点上看可以看到创建的网络,但是在子节点上看时,需要创建完容器后才能看到

sh
docker network ls

测试容器互联链接

56上部署ollama/ollama,在113上部署ghcr.io/open-webui/open-webui:latest

部署ollama/ollama

sh
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:latestOLLAMA_BASE_URL这个环境变量需要参考官方 官方文档)

sh
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
http://10.2.7.113:4000

docker退出集群

子节点退出集群

要退出集群,需要先在需要退出的子节点上退出,然后在在主节点上删除对应的子节点

sh
docker swarm leave --force

当前使用例子,先退出子节点,再退出主节点(是否加上-force的执行结果如图所示) 在主节点查看节点情况,会显示113这台主机的状态为down

主节点删除子节点

主节点需要手动删除该退出集群的节点

sh
docker node rm 节点id或hostname

服务器中docker相关的修复项

docker服务文件目录(docker.service所在位置)

sh
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

验证配置

sh
docker info | grep "Userland Proxy" # Userland Proxy: false

作用

markdown

禁用用户空间代理(Userland Proxy)在 Docker 中的主要作用是提高网络性能和安全性。以下是禁用用户空间代理的一些主要用途和优点:

1. 提高网络性能:

- 减少延迟:用户空间代理会在 Docker 容器和宿主机之间引入额外的网络层,可能导致网络延迟。禁用用户空间代理可以直接使用 Linux 内核的网络堆栈,从而减少延迟。

- 提高吞吐量:通过直接使用内核网络堆栈,禁用用户空间代理可以提高网络吞吐量,尤其是在高负载的情况下。

2. 简化网络配置:

- 避免复杂性:用户空间代理会增加网络配置的复杂性,禁用它可以简化网络设置,减少潜在的配置错误。

3. 增强安全性:

- 减少攻击面:用户空间代理在网络层引入了额外的组件,可能成为攻击的目标。禁用它可以减少潜在的安全风险。

- 直接使用内核功能:通过直接使用内核的网络功能,可以减少中间层的安全隐患。

4. 兼容性:

- 与某些网络驱动程序兼容:某些网络驱动程序(如 macvlan 或 ipvlan)可能与用户空间代理不兼容。禁用用户空间代理可以确保这些驱动程序正常工作。

5. 适用于特定场景:

- 高性能应用:对于需要高性能网络的应用(如实时通信、视频流等),禁用用户空间代理可以提供更好的性能。

- 容器化微服务:在微服务架构中,禁用用户空间代理可以提高服务之间的通信效率。

启用user namespace命名空间

同上,加入--userns-remap=defalut 或者在daemon.json中加入"userns-remap": "default"

验证配置

sh
docker info | grep "Userns" #Userns: enabled

作用:

markdown

用户命名空间(User Namespace)在 Docker 中的主要作用是增强容器的安全性和隔离性。以下是用户命名空间的一些关键用途和好处:

1. 增强安全性:

- 权限隔离:用户命名空间允许容器内的用户与宿主机上的用户进行隔离。即使容器内的用户具有特权(如 root 用户),在宿主机上也不会拥有相应的特权。这意味着即使容器被攻陷,攻击者也无法直接获得宿主机的 root 权限。

- 降低攻击面:通过将容器内的用户映射到宿主机上的非特权用户,减少了潜在的攻击面,降低了安全风险。

2. 资源限制:

- 用户命名空间可以帮助限制容器对宿主机资源的访问。例如,容器内的用户可能无法访问宿主机上的某些文件或设备,从而进一步增强安全性。

3. 更好的隔离:

- 用户命名空间提供了更好的隔离机制,使得不同容器之间的用户和组 ID 不会冲突。这对于运行多个容器的环境尤其重要,可以避免权限和访问问题。

4. 简化权限管理:

- 在某些情况下,用户命名空间可以简化权限管理。通过将容器内的用户映射到宿主机上的特定用户,可以更容易地管理文件和目录的权限。

5. 兼容性:

- 用户命名空间使得在容器中运行需要特权的应用程序(如数据库、Web 服务器等)变得更加安全,而不必担心它们会影响宿主机的安全性。

总结

用户命名空间在 Docker 中的主要作用是提供更强的安全性和隔离性,降低容器对宿主机的潜在风险。通过将容器内的用户与宿主机的用户进行隔离,用户命名空间可以有效地保护宿主机免受容器内潜在攻击的影响。

将容器的根文件系统挂载为只读模式

sh
docker run --read-only -it your_image

挂载特定目录为可写 如果容器内的某些目录需要可写权限(例如,日志目录或临时文件目录),你可以使用 -v 选项将这些目录挂载为可写。例如:

docker run --read-only -v /path/to/writable/dir:/path/in/container -it your_image

dockercompose

version: '3.8'
services:
  my_service:
    image: your_image
    read_only: true
    volumes:
      - /path/to/writable/dir:/path/in/container

验证配置

text
进入容器并尝试修改文件系统来验证配置是否成功

作用

markdown

将容器的根文件系统设置为只读模式具有多种安全性和管理上的好处,以下是一些主要用途和优点:

1. 增强安全性:

- 防止恶意修改:将根文件系统设为只读可以防止容器内的应用程序或攻击者对文件系统进行恶意修改。这在运行不可信或潜在有害的代码时尤其重要。

- 限制攻击面:即使容器被攻陷,攻击者也无法修改系统文件或配置,从而降低了对宿主机的潜在威胁。

2. 数据完整性:

- 保护关键文件:某些关键文件(如配置文件、二进制文件等)不应被修改。将根文件系统设为只读可以确保这些文件的完整性。

- 防止意外更改:在开发和测试环境中,防止开发人员或测试人员意外修改文件系统。

3. 简化故障排除:

- 一致性:只读模式可以确保容器在每次启动时都处于相同的状态,便于调试和故障排除。

- 可预测性:容器的行为更加可预测,因为文件系统不会在运行时发生变化。

4. 资源管理:

- 减少存储需求:只读文件系统可以减少对存储的需求,因为不需要频繁写入数据。

- 提高性能:在某些情况下,只读文件系统可以提高性能,因为系统不需要处理写入操作。

5. 适用于特定场景:

- 静态应用:对于一些静态应用(如 Web 服务器),只读模式是合适的,因为它们不需要修改文件系统。

- 临时容器:在某些临时或短期运行的容器中,使用只读模式可以确保容器在完成任务后不会留下任何持久的更改。

总结

将容器的根文件系统设置为只读模式可以显著增强安全性、保护数据完整性、简化故障排除,并提高资源管理效率。这种做法在运行不可信代码或需要高安全性的环境中尤其重要。

设置on-failure重启策略并限制次数为5

sh
docker run --restart on-failure:5 -it your_image
yaml
version: '3.8'
services:
  my_service:
    image: your_image
    restart: on-failure:5

作用

markdown

设置 Docker 容器的重启策略为 on-failure 并限制重启次数为 5 次具有多种用途和好处,以下是一些主要的优点:

1. 提高容器的可靠性:

- 自动恢复:当容器因错误或故障而停止时,重启策略可以自动尝试重新启动容器。这有助于确保服务的持续可用性,尤其是在处理临时故障时。

2. 减少人工干预:

- 降低运维负担:通过自动重启失败的容器,运维人员不需要手动干预来恢复服务。这可以节省时间和精力,特别是在大规模部署中。

3. 控制重启次数:

- 防止无限重启:通过限制重启次数为 5 次,可以防止容器在持续失败的情况下无限重启。这有助于避免资源浪费和潜在的服务崩溃,确保系统的稳定性。

4. 适应性:

- 应对瞬时故障:在某些情况下,容器可能会因为瞬时故障(如网络问题、临时资源不足等)而停止。重启策略可以帮助容器在这些情况下自动恢复。

5. 监控和告警:

- 触发告警:如果容器在达到重启限制后仍然失败,可以设置监控和告警机制,通知运维人员进行进一步的调查和处理。这有助于及时发现和解决潜在问题。

6. 适用于微服务架构:

- 服务可用性:在微服务架构中,服务之间的依赖关系可能会导致某个服务的失败影响到其他服务。通过设置重启策略,可以提高整个系统的可用性和稳定性。

总结

设置 on-failure 重启策略并限制重启次数为 5 次可以显著提高容器的可靠性,减少人工干预,控制资源使用,并适应瞬时故障。这种配置在生产环境中尤其重要,有助于确保服务的持续可用性和系统的稳定性。

不要共享主机进程命名空间

sh
docker run --pid=private -it your_image
yaml
version: '3.8'
services:
  my_service:
    image: your_image
    pid: "container:other_container_id"  # 共享另一个容器的进程命名空间

查看容器的进程命名空间设置

sh
docker inspect <container_id> --format '{{.HostConfig.PidMode}}'

作用

markdown

在 Docker 中,进程命名空间的设置(如 private、host 和 container:<container_id>)具有不同的作用和用途。以下是每种设置的详细作用:

1. private

- 作用:

- 进程隔离:容器使用自己的进程命名空间,容器内的进程只能看到该容器内的进程,无法访问宿主机或其他容器的进程。

- 安全性:增强了容器的安全性,防止容器内的进程干扰宿主机或其他容器的进程。

- 适用场景:适用于大多数应用场景,尤其是需要高安全性和隔离性的环境。

2. host

- 作用:

- 共享进程视图:容器共享宿主机的进程命名空间,容器内的进程可以看到宿主机上的所有进程。

- 调试和监控:适用于需要与宿主机进程交互的场景,例如调试工具、监控工具或需要访问宿主机服务的应用。

- 性能:在某些情况下,使用宿主机的进程命名空间可以提高性能,因为减少了进程间的隔离开销。

3. container:<container_id>

- 作用:

- 共享进程信息:容器共享另一个容器的进程命名空间,容器内的进程可以访问共享容器的进程信息。

- 紧密协作:适用于需要紧密协作的多个容器,例如在同一进程空间中运行的服务,允许它们相互访问进程信息。

- 资源管理:可以更好地管理资源,特别是在需要多个服务协同工作的场景中。

总结

- private:提供良好的隔离性和安全性,适用于大多数场景。

- host:适用于需要与宿主机进程交互的场景,提供更高的性能和可访问性。

- container:<container_id>:适用于需要共享进程信息的容器,允许它们紧密协作。

选择合适的进程命名空间设置取决于应用的需求、安全考虑和性能要求。

不要共享主机的ipc命名空间

sh
docker run --ipc=private -it your_image
```yaml
version: '3.8'
services:
  my_service:
    image: your_image
    ipc: "private"  # 确保不共享宿主机的 IPC 命名空间

查看容器的 IPC 命名空间设置

sh
docker inspect <container_id> --format '{{.HostConfig.IpcMode}}'

作用

markdown

不共享主机的 IPC(Inter-Process Communication)命名空间具有多种重要作用和好处,以下是主要的作用:

1. 增强安全性

- 隔离性:通过不共享 IPC 命名空间,容器内的进程无法访问宿主机或其他容器的 IPC 资源(如共享内存、信号量等)。这减少了潜在的攻击面,防止恶意进程通过 IPC 进行攻击或数据窃取。

- 防止信息泄露:容器内的进程无法访问宿主机或其他容器的进程间通信,这有助于保护敏感数据和信息,确保数据的隐私性。

2. 提高稳定性

- 避免干扰:如果容器共享 IPC 命名空间,容器内的进程可能会干扰宿主机或其他容器的进程间通信,导致不稳定或不可预测的行为。通过使用独立的 IPC 命名空间,可以避免这种干扰。

- 独立性:每个容器都可以独立运行,确保其进程间通信不会受到其他容器或宿主机进程的影响。

3. 适用于多租户环境

- 资源隔离:在多租户环境中,确保不同用户或服务之间的 IPC 资源隔离是至关重要的。通过不共享 IPC 命名空间,可以确保不同租户之间的资源不会相互干扰,增强了安全性和稳定性。

4. 简化故障排除

- 可预测性:使用独立的 IPC 命名空间可以使容器的行为更加可预测,便于调试和故障排除。开发人员可以更容易地识别和解决问题,而不必担心其他容器的影响。

5. 适用于特定应用场景

- 容器化微服务:在微服务架构中,服务之间的通信通常通过网络进行,而不是通过 IPC。使用独立的 IPC 命名空间可以确保服务之间的通信不会受到影响,增强了系统的可用性和稳定性。

总结

不共享主机的 IPC 命名空间可以显著增强容器的安全性、稳定性和隔离性,防止进程间的干扰和信息泄露。这在需要高安全性和隔离性的应用场景中尤其重要。

不要共享主机的UTS命名空间

sh
docker run --uts=private -it your_image
yaml
version: '3.8'
services:
  my_service:
    image: your_image
    uts: "private"  # 确保不共享宿主机的 UTS 命名空间

在dockercompose中加上uts: "private",或者在docker运行容器时加上--uts=private

查看容器的UTS命名空间设置

sh
docker inspect <container_id> --format '{{.HostConfig.UTSMode}}'

作用

markdown

不共享主机的 UTS(UNIX Time-Sharing)命名空间的主要作用包括以下几个方面:

1. 增强安全性

- 隔离性:通过不共享 UTS 命名空间,容器内的进程无法访问宿主机或其他容器的主机名和域名。这种隔离减少了潜在的攻击面,防止恶意进程通过获取主机名或域名信息进行攻击。

- 防止信息泄露:容器内的进程无法获取宿主机的主机名和域名信息,从而保护敏感数据,确保数据的隐私性。

2. 提高稳定性

- 避免干扰:如果容器共享 UTS 命名空间,容器内的进程可能会干扰宿主机或其他容器的主机名设置,导致不稳定或不可预测的行为。使用独立的 UTS 命名空间可以避免这种干扰,确保每个容器的主机名设置不会影响其他容器或宿主机。

- 独立性:每个容器都可以独立运行,确保其主机名和域名设置不会受到其他容器或宿主机进程的影响。

3. 适用于多租户环境

- 资源隔离:在多租户环境中,确保不同用户或服务之间的 UTS 资源隔离是至关重要的。通过不共享 UTS 命名空间,可以确保不同租户之间的资源不会相互干扰,增强了安全性和稳定性。

4. 简化故障排除

- 可预测性:使用独立的 UTS 命名空间可以使容器的行为更加可预测,便于调试和故障排除。开发人员可以更容易地识别和解决问题,而不必担心其他容器的影响。

5. 适用于特定应用场景

- 容器化微服务:在微服务架构中,服务之间的通信通常通过网络进行,而不是通过 UTS。使用独立的 UTS 命名空间可以确保服务之间的通信不会受到影响,增强了系统的可用性和稳定性。

总结

不共享主机的 UTS 命名空间可以显著增强容器的安全性、稳定性和隔离性,防止进程间的干扰和信息泄露。这在需要高安全性和隔离性的应用场景中尤其重要。通过确保每个容器都有自己的主机名和域名设置,可以提高系统的整体安全性和可靠性。

不要共享主机的user命名空间

sh
docker run --userns=private -it your_image
yaml
version: '3.8'
services:
  my_service:
    image: your_image
    userns: "private"  # 确保不共享宿主机的用户命名空间

查看容器的 user 命名空间设置

sh
docker inspect <container_id> --format '{{.HostConfig.UsernsMode}}'

作用

markdown

不共享主机的用户命名空间(User Namespace)在 Docker 中的主要作用包括以下几个方面:

1. 增强安全性

- 权限隔离:通过不共享用户命名空间,容器内的用户(即使是 root 用户)不会拥有宿主机上的相应权限。这意味着即使容器被攻陷,攻击者也无法直接获得宿主机的 root 权限,从而降低了安全风险。

- 防止权限提升:容器内的用户无法访问宿主机的用户和组信息,减少了通过权限提升攻击获取宿主机资源的可能性。

2. 提高稳定性

- 避免干扰:如果容器共享用户命名空间,容器内的用户可能会干扰宿主机或其他容器的用户和组设置,导致不稳定或不可预测的行为。使用独立的用户命名空间可以避免这种干扰,确保每个容器的用户设置不会影响其他容器或宿主机。

- 独立性:每个容器都可以独立运行,确保其用户和组设置不会受到其他容器或宿主机进程的影响。

3. 适用于多租户环境

- 资源隔离:在多租户环境中,确保不同用户或服务之间的用户资源隔离是至关重要的。通过不共享用户命名空间,可以确保不同租户之间的资源不会相互干扰,增强了安全性和稳定性。

4. 简化故障排除

- 可预测性:使用独立的用户命名空间可以使容器的行为更加可预测,便于调试和故障排除。开发人员可以更容易地识别和解决问题,而不必担心其他容器的影响。

5. 适用于特定应用场景

- 容器化微服务:在微服务架构中,服务之间的通信通常通过网络进行,而不是通过用户命名空间。使用独立的用户命名空间可以确保服务之间的通信不会受到影响,增强了系统的可用性和稳定性。

总结

不共享主机的用户命名空间可以显著增强容器的安全性、稳定性和隔离性,防止进程间的干扰和信息泄露。这在需要高安全性和隔离性的应用场景中尤其重要。通过确保每个容器都有自己的用户和组设置,可以提高系统的整体安全性和可靠性。

限制容器的内存使用

sh
docker run --memory="512m" -it your_image
docker run --memory="1g" -it your_image
  • m:表示兆字节(MB)。
  • g:表示千兆字节(GB)。
  • k:表示千字节(KB)。
yaml
version: '3.8'
services:
  my_service:
    image: your_image
    deploy:
      resources:
        limits:
          memory: 512M  # 限制内存为 512MB

验证内存限制

sh
docker inspect <container_id> --format '{{.HostConfig.Memory}}'

注意事项

  • 内存限制:如果容器使用的内存超过限制,Docker 将会终止该容器。
  • 交换空间:还可以使用 --memory-swap 选项来设置容器的交换空间限制。交换空间是物理内存不足时使用的虚拟内存。例如,设置内存限制为 512MB,交换空间限制为 1GB:
sh
docker run --memory="512m" --memory-swap="1g" -it your_image

作用

markdown
限制 Docker 容器的内存使用具有多种重要作用和好处,以下是主要的作用:

1. 防止资源耗尽

- 保护宿主机:通过限制容器的内存使用,可以防止单个容器消耗过多的内存资源,从而影响宿主机和其他容器的性能。这有助于确保系统的稳定性和可用性。

- 避免 OOM(Out of Memory)杀死:如果容器使用的内存超过宿主机的可用内存,操作系统可能会启动 OOM 杀手来终止进程。通过设置内存限制,可以减少这种情况的发生。

2. 提高性能

- 资源分配:限制内存使用可以确保容器在可控的资源范围内运行,从而提高应用程序的性能。容器在内存限制内运行时,能够更有效地利用可用资源。

- 减少交换:通过限制内存使用,可以减少容器使用交换空间的可能性,从而提高性能。过多的交换会导致性能下降,因为访问磁盘比访问内存慢得多。

3. 增强安全性

- 隔离性:限制容器的内存使用可以增强容器之间的隔离性,防止某个容器的内存使用影响到其他容器或宿主机。这在多租户环境中尤为重要。

- 防止恶意行为:如果容器内的应用程序被攻击或出现故障,限制内存使用可以防止其消耗过多资源,降低潜在的安全风险。

4. 适用于微服务架构

- 资源管理:在微服务架构中,多个服务可能在同一宿主机上运行。通过限制每个容器的内存使用,可以更好地管理资源,确保每个服务都有足够的资源运行。

- 可预测性:设置内存限制可以使容器的行为更加可预测,便于监控和管理。

5. 简化故障排除

- 可控性:通过限制内存使用,可以更容易地识别和解决内存相关的问题。开发人员可以根据内存使用情况进行调试和优化。

总结

限制 Docker 容器的内存使用可以有效地防止资源耗尽、提高性能、增强安全性,并适用于微服务架构。这种做法在生产环境中尤其重要,有助于确保系统的稳定性和可靠性。通过合理设置内存限制,可以更好地管理和优化容器化应用程序的资源使用。