Docker 基础笔记:拉取、执行与常见配置/问题
1. Docker 拉取与执行流程
核心概念: 使用预先配置好的环境(镜像)来运行代码。
基本流程:
- 拉取镜像 (
docker pull
): 从 Docker Hub 等仓库下载一个包含操作系统、运行时和依赖的环境模板。# 示例:拉取轻量级 Python 3.9 镜像 docker pull python:3.9-slim
- 运行容器 (
docker run
): 基于镜像创建一个可运行的实例(容器)。- 交互式运行 (进入容器 Shell):
进入容器后,可执行命令如# -it: 交互式终端, --rm: 容器退出后自动删除, bash: 在容器内执行的命令 docker run -it --rm python:3.9-slim bash
python --version
,用exit
退出。 - 运行本地代码: 需将本地目录挂载到容器内。
# 创建本地脚本 hello.py # echo "print('Hello from my local script!')" > hello.py # -v $(pwd):/app: 将当前目录挂载到容器的 /app 目录 # -w /app: 设置容器内的工作目录为 /app docker run -it --rm -v $(pwd):/app -w /app python:3.9-slim python hello.py
- 交互式运行 (进入容器 Shell):
- 代码执行:
- 运行镜像内置的程序。
- 运行通过卷挂载进来的本地代码。
关键术语:
- 镜像 (Image): 只读模板,定义了环境。
- 容器 (Container): 镜像的运行实例。
- 卷 (Volume):
-v
参数,用于主机与容器间共享目录/数据。 - 端口映射 (Port Mapping):
-p
参数,将容器端口暴露给主机(例如-p 8080:80
)。
为什么使用 Docker?
- 环境一致性: 保证开发、测试、生产环境相同。
- 快速部署: 无需手动配置依赖。
- 隔离性: 应用运行在独立环境中,不影响主机。
2. 故障排除:Permission Denied (docker.sock)
错误信息示例:
permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock...
原因: 当前用户无权访问 Docker 守护进程。
解决方法:
- 使用
sudo
(临时):sudo docker pull python:3.9-slim
- 将用户加入
docker
组 (推荐, 永久):# 1. 将当前用户添加到 docker 组 sudo usermod -aG docker $USER # 2. 重新登录或重启使组生效 (或临时用 newgrp docker) # 3. 验证 (无需 sudo) docker ps
3. 故障排除: “executable file not found” (例如 zsh)
错误信息示例:
OCI runtime create failed: ...: exec: "zsh": executable file not found in $PATH: unknown
原因: 容器镜像(特别是 slim
或 alpine
版)未安装该命令。
解决方法:
- 使用镜像自带命令: 如
bash
或sh
。sudo docker run -it --rm python:3.9-slim bash
- 使用功能更全的镜像: 如标准版
python:3.9
。sudo docker run -it --rm python:3.9 bash
- 构建自定义镜像: 使用
Dockerfile
添加所需工具。# Dockerfile FROM python:3.9-slim RUN apt-get update && apt-get install -y zsh && rm -rf /var/lib/apt/lists/*
# 构建并运行 sudo docker build -t my-python-with-zsh . sudo docker run -it --rm my-python-with-zsh zsh
4. 配置容器网络代理
场景: 容器内应用(如 pip
, apt-get
, curl
)需要通过主机上运行的代理服务器访问外部网络。
问题: 直接在容器内使用 127.0.0.1:<proxy_port>
会失败 (Connection refused),因为容器网络隔离,127.0.0.1
指向容器自身而非主机。
解决方案: 使用特殊 DNS 名 host.docker.internal
指向主机,并设置代理环境变量。
命令示例 (假设主机代理在 7897 端口):
sudo docker run -it --rm \
--add-host=host.docker.internal:host-gateway \
-e HTTP_PROXY=http://host.docker.internal:7897 \
-e HTTPS_PROXY=http://host.docker.internal:7897 \
-e NO_PROXY=localhost,127.0.0.1 \
python:3.9-slim bash
关键参数解释:
--add-host=host.docker.internal:host-gateway
:- 重要: 在 Linux Docker 环境中,此参数将
host.docker.internal
映射到主机的网关 IP,使其可用。 - Docker Desktop (Mac/Windows) 通常内置此映射,此参数可确保跨平台兼容性。
- 重要: 在 Linux Docker 环境中,此参数将
-e HTTP_PROXY=http://host.docker.internal:7897
: 设置 HTTP 代理环境变量,指向主机代理。-e HTTPS_PROXY=http://host.docker.internal:7897
: 设置 HTTPS 代理环境变量。-e NO_PROXY=localhost,127.0.0.1
: 指定哪些地址不走代理(例如容器内部通信)。
验证:
在容器内运行需要联网的命令,如:
pip install requests
curl https://ifconfig.me # 应显示代理服务器 IP
持久化配置:
可以将 ENV
指令添加到 Dockerfile
中,以便构建的镜像默认带有代理配置(注意 host.docker.internal
需要在 docker run
时通过 --add-host
才能在 Linux 上正确解析)。
FROM python:3.9-slim
ENV HTTP_PROXY=http://host.docker.internal:7897
ENV HTTPS_PROXY=http://host.docker.internal:7897
ENV NO_PROXY=localhost,127.0.0.1
# ... 其他指令 ...