云计算:Docker 命令
常用命令
docker version
docker info
docker <命令> --help
# 镜像
docker login -u <用户名>
docker tag <镜像名> <用户名>/<镜像名>
docker images
docker push <用户名>/<镜像名>
docker run -dp <本机端口号>:<容器端口号> <用户名>/<镜像名>
docker rmi -f <image-id>
docker rmi -f $(docker images -aq)
docker image prune # 删除所有未被 tag 标记的虚悬镜像
docker search <镜像名> --filter=STARS=3000 # 搜索镜像,过滤出大于3000星的镜像
docker pull <镜像名>:<tag> # 下载镜像,不写 tag 默认下载 latest 版本
# 容器
docker run -d -p 80:80 --name <容器名> <镜像名> # `-d` - 以分离模式(在后台)运行容器
docker run -dp 80:80 --name <容器名> <镜像名> # `-p 80:80` - 将主机的80端口映射到容器的80端口(-p 为 -publish)
docker run -it <镜像名> /bin/bash # 进入交互式容器,退出命令为 exit,`Ctrl + P + Q` 为不停止退出交互式容器
docker exec -d <container-name/container-id> <命令> # 在容器后台运行命令
docker exec -it <container-name/container-id> /bin/bash # 进入容器后开启一个新的终端
docker attach --sig-proxy=false <container-name/container-id> # 进入容器正在执行的终端,不会启动新的进程
docker ps
docker ps -a
docker ps --all
docker start <container-name/container-id>
docker stop <container-name/container-id>
docker restart <container-name/container-id>
docker kill <container-name/container-id>
docker rm <container-id>
docker rm <container-id> <container-id> <container-id> <container-id>
docker rm -f <container-id> # 强制移除容器(包括正在运行的)
docker rm -f $(docker ps -aq) # 强制移除所有容器
docker top <container-id> # 查看容器进程信息
docker inspect <container-id> # 查看容器内部信息
# 文件拷贝
docker cp <container-id>:<容器中的文件> <拷贝到本机的目录> # 文件从容器拷贝到宿主机
docker cp <本机文件> <container-id>:<容器中的文件的目录> # 文件从宿主机拷贝到容器
# 命名卷
docker volume create <卷名>
docker volume list
docker run -dp <本机端口号>:<容器端口号> -v <卷名>:<容器中的挂载目录> <用户名>/<镜像名> # 自动创建指定的卷,默认存放路径 `/var/lib/docker/volumes/<卷名>/_data`
docker volume inspect <卷名> # 查看卷的详细信息
# 绑定挂载
docker run -dp 3000:3000 \
-w /app \ # 设定「工作目录」或指令运行的工作目录
-v "$(pwd):/app" \ # 将当前工作目录挂载到容器里面的`/app`目录
node:12-alpine \ # 要使用的镜像及版本
sh -c "yarn install && yarn run dev" # 用 `sh -c` 开启一个 shell 执行字符串中的内容
# 通过日志来查看内部的执行信息,按 `Ctrl+C` 退出
docker logs -f <container-id>
docker logs -tf --tail 10 <container-id>
# 网络
docker network create <网络名>
docker network create -d bridge <网络名> # 创建一个桥接网络
docker network list
docker run -d \
--network <网络名> \
--network-alias <网络别名> \
-v <卷名>:<容器中的挂载目录> \
-e MYSQL_ROOT_PASSWORD=<root用户密码> \
-e MYSQL_DATABASE=<数据库名> \
mysql:5.7
docker exec -it <mysql-container-id> mysql -u root -p # 进入容器,并执行命令
docker run -it --network <网络名> nicolaka/netshoot # 用 DNS 工具查找主机名 mysql 的 IP 地址
dig mysql # 查找主机名 mysql 的 IP 地址,虽然 mysql 不是一个有效的主机名,但 Docker 可以将其解析为具有该网络别名的容器的 IP 地址
Dockerfile
Dockerfile 文件
# syntax=docker/dockerfile:1
# 指向版本1语法的最新版本,在构建之前自动检查语法更新,确保您使用的是最新版本。必须始终位于 Dockerfile 的顶部。
# 文件中的注释以 `#` 符号开头,并且必须在一行的开头。
ARG IMAGE_NAME=<镜像名> # 相当于定义变量,在多阶段构建时根据阶段区分作用域,写在 FROM 外面为全局变量
##
## Build
##
FROM ${IMAGE_NAME} as <镜像别名>
# 用来给镜像以键值对的形式添加一些元数据(metadata),还可以用一些标签来申明镜像的作者、文档地址等
LABEL
ENV <环境变量名>=<环境变量值>
WORKDIR <指定的根目录/命令执行的位置>
# ADD 在 COPY 基础上增加了一些功能,这个功能其实并不实用,而且不推荐使用
# 所有的文件复制均使用 COPY 指令,仅在需要自动解压缩的场合使用 ADD
COPY <本地文件名> <本地文件名> <拷贝到镜像中以 WORKDIR 为根的目录>
RUN <构建时运行的命令>
CMD ["<命令1>", "<命令2>", "<命令3>"] # 指定从此镜像启动容器时运行的默认命令
##
## Deploy
##
FROM <镜像名> as <镜像别名>
WORKDIR <指定的根目录/命令执行的位置>
COPY --from=<上阶段的镜像别名/可用0代替> <上阶段构建好的文件及路径> <移入本阶段的镜像中以 WORKDIR 为根的目录>
# 在 Dockerfile 中写入这样的声明有两个好处,一个是帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射;
# 另一个用处则是在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。
# EXPOSE 仅仅是声明容器打算使用什么端口而已,并不会自动在宿主进行端口映射
EXPOSE <暴露的端口号>
# 指定 RUN, CMD, ENTRYPOINT 这类命令的身份
USER <用户身份/用户名>
# 入口点,当指定了 ENTRYPOINT 后,CMD 的含义就发生了改变,不再是直接的运行其命令,而是将 CMD 的内容作为参数传给 ENTRYPOINT 指令
ENTRYPOINT ["<命令>"]
CMD ["<参数1>", "<参数2>", "<参数3>"]
命令
docker build --tag docker-gs-ping:latest . # :latest 可以省略不写,默认为 latest
docker image tag docker-gs-ping:latest docker-gs-ping:v1.0 # image 可以省略
docker build -t docker-gs-ping:multistage -f Dockerfile.multistage . # -f 指定自定义的 Dockerfile 文件名
Docker Compose
docker run -dp 3000:3000 \
-w /app \
-v "$(pwd):/app" \
--network todo-app \
-e MYSQL_HOST=mysql \
-e MYSQL_USER=root \
-e MYSQL_PASSWORD=123456 \
-e MYSQL_DB=todos \
node:12-alpine \
sh -c "yarn install && yarn run dev"
docker-compose.yml
version: "3.7"
services:
app: # 服务名
image: node:12-alpine # 镜像名
command: sh -c "yarn install && yarn run dev" # 用 `sh -c` 开启一个 shell 执行字符串中的内容
ports:
- 3000:3000
working_dir: /app # 等同于上面的 (-w /app)
volumes: # 等同于上面的 (-v "$(pwd):/app")
- ./:/app # Docker Compose 卷的优点是可以使用 当前目录的相对路径
environment: # 传递环境变量
MYSQL_HOST: mysql
MYSQL_USER: root
MYSQL_PASSWORD: secret
MYSQL_DB: todos
mysql:
image: mysql:5.7
volumes:
- todo-mysql-data:/var/lib/mysql
environment:
MYSQL_ROOT_PASSWORD: 123456
MYSQL_DATABASE: todos
volumes: # Compose 运行时不会自动创建指定的卷,需要在 top-level volumes 中定义卷,然后在服务配置中指定挂载点。
todo-mysql-data: # 只需提供卷名,将使用默认选项
默认情况下,Docker Compose 会自动为应用程序堆栈创建一个网络(这就是为什么我们没有在 Compose 文件中定义一个网络)。
docker-compose up -d
docker-compose up --build -d # 如果不提供 --build 标志,源代码的更新不触发重新生成
docker-compose logs -f
docker-compose logs -f app # 查看特定服务的日志
docker-compose config
docker-compose stop
docker-compose down # 默认情况下,在文件中的已命名卷不会被删除。如果要删除卷,则需要添加 --volume 标志
安全
docker scan --login
docker scan <镜像名>
镜像分层
docker image history getting-started
docker image history --no-trunc getting-started
应用示例
Dockerfile
下载一个demo:https://github.com/docker/getting-started/tree/master/app
Dockerfile
# syntax=docker/dockerfile:1
FROM node:12-alpine
WORKDIR /app
COPY package.json yarn.lock ./
RUN yarn install --production
COPY . .
EXPOSE 3000
CMD ["node", "src/index.js"] # CMD 指令指定从此图像启动容器时运行的默认命令
.dockerignore
在这种情况下,应该在第二个 COPY 步骤中省略 node_modules 文件夹,因为它可能会覆盖 RUN 步骤中命令创建的文件。
node_modules
# 构建镜像
docker build -t <镜像名> .
多阶段构建
# syntax=docker/dockerfile:1
FROM maven AS build
WORKDIR /app
COPY . .
RUN mvn package
FROM tomcat
COPY --from=build /app/target/file.war /usr/local/tomcat/webapps
# syntax=docker/dockerfile:1
FROM node:12 AS build
WORKDIR /app
COPY package* yarn.lock ./
RUN yarn install
COPY public ./public
COPY src ./src
RUN yarn run build
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
克隆项目
git clone https://github.com/olliefr/docker-gs-ping
dockerfile.multigrade
# syntax=docker/dockerfile:1
# 指向版本1语法的最新版本,在构建之前自动检查语法更新,确保您使用的是最新版本。必须始终位于 Dockerfile 的顶部。
# 文件中的注释以 `#` 符号开头,并且必须在一行的开头。
##
## Build
##
# 指定应用程序使用的基础镜像
FROM golang:alpine AS builder
LABEL maintainer="toki@toki-plus@qq.com" \
version="v1.0" \
description="描述信息" \
date="2022-04-11"
ENV CGO_ENABLED 0
ENV GOOS linux
ENV GOARCH amd64
# 指示 Docker 使用此目录作为所有后续命令的执行位置
WORKDIR /app
# 将 `go.mod` 和 `go.sum` 文件复制到镜像的 /app 目录中
COPY go.mod go.sum ./
# 设置 go 的初始环境变量,下载 mod 依赖
RUN go env -w GO111MODULE=on \
&& go env -w GOPROXY=https://goproxy.cn,direct \
&& go mod download \
&& go mod verify
# 将 go 后缀的文件移入镜像
COPY *.go ./
# 编译可执行文件,去掉了调试信息 -ldflags="-s -w" 以减小镜像尺寸
RUN go build -ldflags="-s -w" -o /docker-gs-ping
##
## Deploy
##
# 引用小型操作系统
FROM alpine:latest as deployer
# 使用 Alpine 基础镜像,安装软件包时需要用 apk 包管理器
RUN apk update --no-cache && apk add --no-cache ca-certificates tzdata
ENV TZ Asia/Shanghai
WORKDIR /
# 继承上一阶段的 builder 镜像,并拷贝生成的可执行文件
COPY --from=builder /docker-gs-ping /docker-gs-ping
# 暴露端口
EXPOSE 8080
USER nonroot:nonroot
# 入口点
ENTRYPOINT ["/docker-gs-ping"]
用 -t
为镜像添加标签,例如 <镜像名:版本号>
用 -f
指定自定义的 Dockerfile 文件名,默认的文件名为 Dockerfile
最后的 .
表示 Dockerfile 所在的位置
docker build -t docker-gs-ping:multistage -f Dockerfile.multistage .
docker run --publish 8080:8080 docker-gs-ping
打开新的命令行
curl http://localhost:8080/
已分离模式运行
docker run -d -p 8080:8080 --name rest-server docker-gs-ping
curl http://localhost:8080/
储存
# 创建卷
docker volume create roach
# 查看卷
docker volume list
网络
# 创建一个桥接网络
docker network create -d bridge mynet
# 查看网络
docker network list
启动数据库引擎
docker run -d \
--name roach \
--hostname db \
--network mynet \
-p 26257:26257 \
-p 8080:8080 \
-v roach:/cockroach/cockroach-data \
cockroachdb/cockroach:latest-v20.1 \
start-single-node --insecure
配置数据库引擎
docker exec -it roach ./cockroach sql --insecure
CREATE DATABASE mydb;
CREATE USER totoro;
GRANT ALL ON DATABASE mydb TO totoro;
quit
示例应用
git clone https://github.com/olliefr/docker-gs-ping-roach.git
docker build --tag docker-gs-ping-roach .
docker run -it --rm -d \
--network mynet \
--name rest-server \
-p 80:8080 \
-e PGUSER=totoro \
-e PGPASSWORD=myfriend \
-e PGHOST=db \
-e PGPORT=26257 \
-e PGDATABASE=mydb \
docker-gs-ping-roach
curl localhost
# 或 curl http://localhost/
curl --request POST \
--url http://localhost/send \
--header 'content-type: application/json' \
--data '{"value": "Hello, Docker!"}'
docker container stop rest-server roach
docker container rm rest-server roach
docker container list --all
docker run -d \
--name roach \
--hostname db \
--network mynet \
-p 26257:26257 \
-p 8080:8080 \
-v roach:/cockroach/cockroach-data \
cockroachdb/cockroach:latest-v20.1 start-single-node \
--insecure
docker run -it --rm -d \
--network mynet \
--name rest-server \
-p 80:8080 \
-e PGUSER=totoro \
-e PGPASSWORD=myfriend \
-e PGHOST=db \
-e PGPORT=26257 \
-e PGDATABASE=mydb \
docker-gs-ping-roach
curl localhost
docker container list
Docker Compose
docker-compose.yml
version: '3.8'
services:
docker-gs-ping-roach:
depends_on:
- roach
build:
context: .
container_name: rest-server
hostname: rest-server
networks:
- mynet
ports:
- 80:8080
environment:
- PGUSER=${PGUSER:-totoro}
- PGPASSWORD=${PGPASSWORD:?database password not set}
- PGHOST=${PGHOST:-db}
- PGPORT=${PGPORT:-26257}
- PGDATABASE=${PGDATABASE:-mydb}
deploy:
restart_policy:
condition: on-failure
roach:
image: cockroachdb/cockroach:latest-v20.1
container_name: roach
hostname: db
networks:
- mynet
ports:
- 26257:26257
- 8080:8080
volumes:
- roach:/cockroach/cockroach-data
command: start-single-node --insecure
volumes:
roach:
networks:
mynet:
driver: bridge
docker compose 将自动从 .env
文件中读取环境变量。由于 Compose 文件要求设置 PGPASSWORD,因此我们将以下内容添加到 .env
文件
PGPASSWORD=whatever
docker-compose config
docker-compose up --build -d
docker exec -it roach ./cockroach sql --insecure
curl http://localhost/
docker-compose stop
docker-compose down