Docker
Command
登录
docker login
查看信息
# version
docker version
docker info
# 查看系统信息
docker system info
# ps
docker ps
# 查看容器信息
docker inspect container_name/container_id
# 查看容器运行日志
docker logs container_name/container_id
# 查看尾部日志并跟踪
docker logs --tail 10 -f container_name/container_id
# 查看容器端口映射
docker port container_name
# 查看容器占用资源
docker stats
镜像
# search images
docker search python
# list images
docker image ls
# download image
docker pull python:latest
# commit image
docker commit -m "comment" -a "author" container_id my_hub/my_image:tag
# push image
docker login
docker tag my_image my_hub/my_image
docker push my_hub/my_image
# remove image
docker rmi my_image:tag
docker image prune
# save image
docker save -o my_image.tar my_hub/my_image
# load image
docker load --input my_image.tar
Build
# build
docker build -t ${NAME}:${VERSION} .
# build with Dockerfile
docker build -t ${NAME}:${VERSION} -f path/to/Dockerfile ./
# build with host network
docker build --network=host -t ${NAME}:${VERSION} ./
# build with env args
docker build --build-arg env=$(ENV) -t ${NAME}:${VERSION} .
# build to target stage
docker build --target base -t ${NAME}:${VERSION} .
容器
# list containers
docker container ls
docker container ls -a
# start container
docker start container_name/container_id
docker stop container_name/container_id
# remove container
docker rm container_name
docker rm container_id
docker container prune
# 文件互传
docker cp /file/in/host container_name:/file/in/container # 将文件推入容器
docker cp container_name:/file/in/container /file/in/host # 从容器拉取文件
Run
# run in a new container
docker run -it --name='test' python bash
# run in a running container
docker exec -it container_name bash
# 后台运行
docker run -d python
# 自动重启
docker run -d --restart unless-stopped python
# 环境变量
docker run --env ENV1=env1 python
# 资源限制
docker run --cpus=".5" --memory=1g python
Data
# 创建数据卷
docker volume create my-vol
# 查看所有的数据卷
docker volume ls
# 查看数据卷信息
docker volume inspect my-vol
# 启动一个挂载数据卷的容器
docker run -it -v my-vol --name test ubuntu bash
# 删除数据卷
docker volume rm my-vol
# 清理数据卷
docker volume prune
# 挂载本地文件夹作为数据卷
docker run -it -v $(pwd)/test:/test --name test ubuntu bash
# 设置只读权限
docker run -it -v $(pwd)/test:/test:ro --name test ubuntu bash
Network
- 通过映射端口或者主机网络模式,使得容器可以对外提供服务
- 通过创建并加入容器网络,或者link(已废弃),使得容器可以互联
# 查看网络
docker network ls
# 创建网络
docker network create my-net
# 加入网络
docker run -it --network=my-net --name test ubuntu
docker network connect my-net container_name
# 清理网络
docker network prune
# 映射容器的80端口到主机的8000端口
docker run -it -p 8000:80 --name test ubuntu
# 映射到主机的49000~49900中随机一个端口
docker run -it -P --name test ubuntu
# 映射容器的80端口到主机的8000端口,限定只有本地可以访问
docker run -it -p 127.0.0.1:8000:80 --name test ubuntu
# 以主机网络模式运行
docker run -it --net=host --name test ubuntu
docker run -it --network host --name test ubuntu
# 以桥接模式运行(默认模式)
docker run -it --network bridge --name test ubuntu
# 创建连接
docker run -d --name my_db postgres
docker run -d -P --name web --link my_db:db webapp python app.py
Dockerfile
- FROM: 继承镜像
- COPY: 复制文件
- 目标路径不需要事先创建,如果目录不存在会在复制文件前先行创建缺失目录。
- 源路径可以是多个,甚至可以是通配符,例如
COPY hom?.txt /mydir/
- 如果源路径是文件夹,会把源文件夹下的文件拷贝过去,例:
COPY dir1 dir2 ./
等价于COPY dir1/* dir2/* ./
- 使用
--chown=<user>:<group>
来改变文件的所属用户及所属组,例如:COPY --chown=55:mygroup files* /mydir/
- WORKDIR: 工作路径
- RUN: 执行命令
- EXPOSE: 暴露端口,(本身只是提示哪个端口提供服务,实际需要运行时通过-p映射到主机端口才能访问)
- ENTRYPOINT: 入口命令,后面传参时不会覆盖命令
- CMD: 主命令,(不能用于启动后台service)
- ENV: 设置环境变量
示例
FROM python:latest
ARG env=dev
COPY . /app
WORKDIR /app
RUN pip install web.py
RUN chmod 755 main.py
COPY .env.$env .env
CMD ["python", "main.py"]
EXPOSE 8080
Build Dockerfile
docker image build -t webpy:0.1 .
Run after build
docker run -p 8080:8080 -d --name webpy-test webpy:0.1
使用supervisord启动多个服务
配置文件配置服务
[supervisord]
nodaemon = true # 是否前台运行,true为前台运行
# 配置服务1
[program:openapi]
priority = 1 # 优先级
command = uvicorn api.main:app --host 0.0.0.0 --port 30050 # 启动命令
redirect_stderr = true # 是否重定向输出
stdout_logfile = /usr/src/app/logs/openapi.log # 重定向输出文件
stderr_logfile = /usr/src/app/logs/openapi.err # 重定向错误文件
# 配置服务2
[program:python]
priority = 2
command = python ./python/main.py
redirect_stderr = true
stdout_logfile = /usr/src/app/logs/python.log
stderr_logfile = /usr/src/app/logs/python.err
编写Dockerfile
# 安装
RUN apt-get -y update \
&& apt-get -y install \
supervisor \
&& apt-get clean
# 复制配置文件
COPY supervisord/supervisord.conf /root/supervisord.conf
# 启动
CMD ["/usr/bin/supervisord", "-c", "/root/supervisord.conf"]
使用心得
- 快速上手新技术,将精力集中于语言本身而非环境配置
- 将技术栈的常用框架docker化,快速进行新研究
- 将自己代码或项目docker化,以后可以快速调用和交付
常用环境
Java
FROM maven:3-openjdk-8-slim AS BUILD
COPY pom.xml /tmp/
COPY src /tmp/src/
WORKDIR /tmp/
RUN mvn package
FROM openjdk:8-alpine AS RUNTIME
RUN apk update && apk add --no-cache libc6-compat
RUN ln -s /lib64/ld-linux-x86-64.so.2 /lib/ld-linux-x86-64.so.2
WORKDIR /app/
COPY --from=BUILD /tmp/target/logstreams-0.1-jar-with-dependencies.jar .
COPY src/main/resources ./resources
ENTRYPOINT ["java", "-cp", "*", "streams.LogStreams"]
Python
FROM python:3.10.12-slim
ENV TZ=Asia/Shanghai
ENV LANG zh_CN.UTF-8
WORKDIR /app
COPY ./requirements.txt /app/
RUN pip3 install -i https://pypi.mirrors.ustc.edu.cn/simple --upgrade pip && \
pip3 install -i https://pypi.mirrors.ustc.edu.cn/simple --no-cache-dir -r requirements.txt
COPY ./src .
COPY .env ./
EXPOSE 8080
ENTRYPOINT ["python3", "main.py"]
Vue3 + Vite + Nginx
添加 Nginx 配置文件:
worker_processes 4;
events { worker_connections 1024; }
http {
server {
listen 8080;
root /usr/share/nginx/html/app;
include /etc/nginx/mime.types;
location /app/ {
root /usr/share/nginx/html;
try_files $uri $uri/ /app/index.html;
}
}
}
Dockerfile:
FROM node:18-alpine AS build-stage
COPY package.json ./
RUN npm config set registry https://registry.npmmirror.com && npm install
COPY ./ .
RUN npm run build
FROM nginx:alpine as production-stage
ENV TZ=Asia/Shanghai
COPY nginx.conf /etc/nginx/nginx.conf
RUN rm -rf /usr/share/nginx/html/*
COPY --from=build-stage /dist /usr/share/nginx/html/app
EXPOSE 8080
# set the container to run Nginx in the foreground
ENTRYPOINT ["nginx", "-g", "daemon off;"]
Nuxt
Dockerfile
ARG NODE_VERSION=18.19.1
ARG PORT=3000
FROM node:${NODE_VERSION}-slim as base
ENV NODE_ENV=production
WORKDIR /src
# Build
FROM base as build
COPY --link package.json package-lock.json ./
RUN npm install --production=false
COPY --link . .
RUN npm run build
RUN npm prune
# Run
FROM base
ENV PORT=$PORT
COPY --from=build /src/.output /src/.output
# Optional, only needed if you rely on unbundled dependencies
# COPY --from=build /src/node_modules /src/node_modules
CMD [ "node", ".output/server/index.mjs" ]
Go
初始化项目
go mod init YOUR_PROJECT
go mod tidy
Dockerfile:
FROM golang:1.20.2
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
WORKDIR /app
# V1: go mod init in builder
COPY *.go ./
RUN go mod init godemo && go mod tidy
RUN CGO_ENABLED=0 GOOS=linux go build -o /godemo
# V2: go mod tidy locally and download Go modules in builder
#COPY go.mod go.sum ./
#RUN go mod download
#COPY *.go ./
#RUN CGO_ENABLED=0 GOOS=linux go build -o /godemo
# V3: copy excutable to container
#COPY build/godemo /
COPY .env ./
EXPOSE 8080
CMD ["/godemo"]
参考:Docker.Docs - Build your Go image
其他
给普通用户添加权限
sudo groupadd docker
sudo gpasswd -a ${USER} docker
sudo systemctl restart docker
sudo chmod a+rw /var/run/docker.sock
设置国内源
sudo vi /etc/docker/daemon.json
写入以下内容
{
"registry-mirrors" : [
"https://mirror.ccs.tencentyun.com"
]
}
重启docker服务
systemctl restart docker.service
远程构建
更改 docker 源只能解决 docker pull 时慢的问题,如果需要在构建阶段进行下载,例如 apt update
、pip install
之类的操作则需要替换对应的源
替换 pip 的源相对简单,可以在 pip 命令时指定源,例如 pip install -i https://pypi.mirrors.ustc.edu.cn/simple requests
替换 apt 源则比较麻烦,因为不同的 base image 可能碰到不一样的问题。例如 python-slim 镜像需要替换 /etc/apt/sources.list
文件,添加国内源后会报公钥验证的错误,见 How can I write a Dockerfile based on Debian Slim in which ‘apt-get update’ doesn’t fail with public key errors?,根据网上教程添加公钥,又会报请先安装 gnupg:E: gnupg, gnupg2 and gnupg1 do not seem to be installed, but one of them is required for this operation,想要安装 gnupg,要先执行 apt-update
。我本来就是为了执行 apt-update
,整闭环了。
使用 HTTP_PROXY/HTTPS_PROXY 环境变量设置代理,但是不支持 SOCKS 代理
使用 proxychains docker build ...
,但是它只对 docker CLI 的客户端生效,构建实际发生在 dockerd 的服务端,因此该配置无效,参考 docker国内镜像加速无效的解决办法
因此考虑在远程(境外)服务器进行构建的方式,参考Can I build a Docker container from the CLI against a remote daemon? 和 How to Use a Remote Docker Server to Speed Up Your Workflow
ssh-copy-id root@remote_host
export DOCKER_HOST=ssh://root@remote_host
# check docker server info
docekr info | grep Name
# build with remote docker server
docker build -t test:0.1 .
# unset environment
unset DOCKER_HOST
但是构建完还是需要 pull 回来
使用 GPU
Installing the NVIDIA Container Toolkit
curl -s -L https://nvidia.github.io/libnvidia-container/stable/rpm/nvidia-container-toolkit.repo | \
sudo tee /etc/yum.repos.d/nvidia-container-toolkit.repo
sudo yum install -y nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker
test
docker run --gpus all nvidia/cuda:latest nvidia-smi
修改存储目录
Relocating the Docker root directory
- Stop the Docker services
sudo systemctl stop docker
sudo systemctl stop docker.socket
sudo systemctl stop containerd
- Move data
sudo mkdir -p /data/docker
sudo mv /var/lib/docker /data/docker
- Change
/etc/docker/daemon.json
{
"data-root": "/data/docker"
}
- Restart & Verify
sudo systemctl start docker
docker info -f '{{ .DockerRootDir}}'
问题
pull或push时证书过期
x509:certificate has expired or is not yet valid
sudo vi /etc/docker/daemon.json
写入以下内容
{
"insecure-registries" : [
"host:port"
]
}
检查网络
docker run --rm -it jonlabelle/network-tools
pip 无法安装
Temporary failure in name resolution Errno -3 with Docker
在 docker build 时使用到的的 pip install
无法安装
解决方法,重启一下 dockerd 服务
sudo service docker restart
docker-compose
install
sudo apt install docker-compose
commands
# up
docker-compose up -d
# down
docker-compose down
# with file
docker-compose -f ${DOCKER_COMPOSE_FILE} up -d