Docker 是什么
特点
使用容器化技术,给应用程序封装独立的运行环境。Docker 容器与虚拟机之间的差别就是,docker 容器共用一个系统,比虚拟机更小,启动更快。解决了因为环境不同无法运行的问题,减少了安装部署应用的时间。
镜像
镜像是一个只读的模板,用于创建 Docker 容器。 它包含了运行应用程序所需的一切:代码、运行时库、环境变量和配置文件。相当于软件安装包。
安装
Docker
删除旧版本
sudo apt-get remove docker docker-engine docker.io containerd runc
设置仓库
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
安装 docker engine
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
验证
sudo docker run hello-world
新版本 docker 自带 docker compose
。
容器
容器是镜像的运行实例。 它是根据镜像创建的应用和环境的集合体
镜像仓库
Docker Hub:是 Docker 官方提供的最大、最常用的公共仓库,包含了海量的官方和第三方镜像。当执行 docker pull
时,Docker 会从配置的仓库中拉取镜像;执行 docker push
时,则会将你本地的镜像推送到仓库中。
Docker 命令
命令 | 含义 | 作用 |
---|---|---|
docker images | 镜像 | 列出本地所有镜像 |
docker pull | 拉取 | docker pull nginx 拉取 nginx 镜像 |
docker push | 推送 | 将本地镜像推送到远程仓库 |
docker rmi | Remove image (删除镜像) | 删除镜像 |
docker ps | process status (进程状态) | 查看正在运行的容器, -a 可以列出所有状态的容器 |
docker stop | 停止 | 停止一个或者多个容器 |
docker start | 启动 | 启动一个或者多个容器 |
docker rm | Remove (删除) | 删除容器,-f (force)可以强制删除正在运行的容器 |
docker kill | 杀死 | 强制关闭一个容器 |
docker pause | 暂停 | 暂停容器内所有进程 |
docker exec | Execute(执行) | 进入容器内部执行命令,常用docker exec -it <容器ID> /bin/bash |
docker logs | 日志 | 查看日志,-f (follow) 实时跟踪日志 |
docker volume | 卷 | ls 查看卷列表,rm <卷名>删除卷 |
docker inspect | 检查 | docker inspect <容器名称或ID> |
Docker run
Docker pull 和 docker run 可以一步到位使用 docker run 命令。
docker run \
-d \
--name my-postgres-db \
-p 127.0.0.1:5432:5432 \
-v postgres_data:/var/lib/postgresql/data \
-e POSTGRES_USER=myuser \
-e POSTGRES_PASSWORD=mysecretpassword \
-e PGDATA=/var/lib/postgresql/data/pgdata \
--network my-custom-net \
--restart unless-stopped \
--memory="1g" \
--cpus="0.5" \
- -d 后台运行
- --name 给容器命名
- -p 端口映射
- -v 挂载 postgres_data 是命名卷挂载,/var/lib/postgresql/data 是PostgreSQL镜像官方指定的、用于存储数据库文件的目录。
- -e 环境变量
- --network 创建并连接一个自定义网络。连接到同一个自定义网络 (
my-custom-net
) 的容器,可以通过容器名作为DNS主机名直接互相通信。
Docker compose
多应用编排,简化了 docker run。
# 定义所有服务
services:
# Caddy 服务 (Web 服务器)
caddy:
restart: unless-stopped # 设置重启策略
image: caddy:latest # 使用的镜像
container_name: server-caddy # 容器名称
ports:
- "443:443" # 端口映射,将宿主机的443端口映射到容器的443
volumes:
- "./data:/www/wwwroot" # 挂载网站根目录
- "./config:/etc/caddy" # 挂载Caddy配置文件目录
- "./logs:/www/wwwlogs" # 挂载日志目录
networks:
- typecho-network # 连接到指定网络
# PHP 服务
php:
restart: unless-stopped
container_name: server-php
image: johnsonran/server-php:latest
volumes:
- "./data:/www/wwwroot" # 与Caddy共享网站文件
networks:
- typecho-network
# MariaDB 服务 (数据库)
mariadb:
restart: unless-stopped
image: mariadb:latest
container_name: server-mariadb
ports:
- "127.0.0.1:3306:3306" # 仅限本机访问数据库
environment:
- MARIADB_ROOT_PASSWORD=PMA_PASSWD # 设置数据库root密码
networks:
- typecho-network
# phpMyAdmin 服务 (数据库Web管理工具)
pma:
restart: unless-stopped
image: phpmyadmin:latest
container_name: server-pma
ports:
- "8283:80" # 将容器的80端口映射到宿主机的8283
environment:
- PMA_HOST=server-mariadb # 告诉pma,数据库主机是名为'server-mariadb'的容器
- PMA_PORT=3306 # 数据库端口
networks:
- typecho-network
# 定义网络
networks:
typecho-network:
driver: bridge # 使用桥接模式网络
将上述内容保存为 docker compose.yml
文件后,在该文件所在目录执行以下命令:
docker compose up -d
: 启动所有服务并在后台运行。- docker compose stop <服务名> : 暂停容器。
- docker compose start <服务名>: 启动容器。
- docker compose restart <服务名>: 启动容器。常用于修改配置之后的重启。
docker compose down
: 删除所有相关的容器和网络。docker compose ps
: 查看所有服务的当前状态。docker compose logs -f <服务名>
: 实时查看指定服务的日志。
网络
- Bridge (桥接模式): 这是 Docker 的默认网络模式。Docker 会创建一个虚拟网桥(如
docker0
),所有此模式下的容器都会连接到这个网桥上,并被分配一个独立的 IP 地址。容器之间可以通过 IP 或容器名(如果连接在同一个自定义桥接网络中)通信。 - Host (主机模式): 容器将不会拥有自己独立的网络命名空间,而是直接共享宿主机的网络。性能最高,但牺牲了隔离性。
- Overlay (覆盖网络): 用于连接运行在不同宿主机上的 Docker 容器,是实现多机容器集群通信(如 Docker Swarm)的关键。
- None (无网络模式): 容器拥有自己的网络命名空间,但不进行任何网络配置。适合对网络安全要求极高或不需要联网的场景。
如果不同编排下的 docker 容器需要用到同一个 web 服务器反代,可以这样写:
services:
onenav:
image: helloz/onenav
container_name: onenav
volumes:
- /data/onenav:/data/wwwroot/default/data
restart: always
expose: # 将容器的80端口暴露给同一docker网络中的其他服务
- "80"
networks:
- onenav # 将服务连接到下面的网络别名
networks:
onenav:
external: true
name: typecho_typecho-network # 实际外部网络名称
这个 docker compose 并没有创建一个 onenav 的网络,external:true 的意思是不用创建 onenav 网络,而是将容器连接到 name:typecho 的网络。当外部 typpecho 这个网络不存在,这个 docker compose 会启动失败。
解决 ufw 和 docker 的问题
Docker 的开放的端口默认会绕过 ufw,如果像让 docker 端口受 ufw 控制可以有以下设置。
修改 UFW 的配置文件
/etc/ufw/after.rules
在最后添加上如下规则:
# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-docker-logging-deny - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j ufw-user-forward
-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16
-A DOCKER-USER -p udp -m udp --sport 53 --dport 1024:65535 -j RETURN
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j ufw-docker-logging-deny -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
-A DOCKER-USER -j RETURN
-A ufw-docker-logging-deny -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW DOCKER BLOCK] "
-A ufw-docker-logging-deny -j DROP
COMMIT
# END UFW AND DOCKER
然后重启 UFW
sudo systemctl restart ufw
现在外部就已经无法访问 Docker 发布出来的任何端口了,但是容器内部以及私有网络地址上可以正常互相访问,而且容器也可以正常访问外部的网络。可能由于某些未知原因,重启 UFW 之后规则也无法生效,请重启服务器。
如果还是无法生效,尝试修改:
/etc/ufw/before.rules
如果希望允许外部网络访问 Docker 容器提供的服务,比如有一个容器的服务端口是 80
。那就可以用以下命令来允许外部网络访问这个服务:
ufw route allow proto tcp from any to any port 80
如果有多个容器的服务端口为 80,但只希望外部网络访问某个特定的容器。比如该容器的私有地址为 172.17.0.2
,就用类似下面的命令:
ufw route deny from 172.17.0.9 to any
docker ps
docker inspect [您的容器名或ID] | grep "IPAddress"
参考
- Docker Docs
- 🎉 Docker 简介和安装 - Docker 快速入门 - 易文档
- 40分钟的Docker实战攻略,一期视频精通Docker\_哔哩哔哩\_bilibili
- GitHub - chaifeng/ufw-docker: To fix the Docker and UFW security flaw without disabling iptables
评论区(暂无评论)