Docker
Docker简介
- docker镜像
容器取代虚拟机真正的原因是Docker发明的镜像,所谓Docker镜像,其实就是一个压缩包,它由一个完整操作系统的所有文件和目录构成,这个压缩包里的内容跟你本地开发和测试环境用的操作系统是完全一样的。
- 镜像是一层一层构建的(分层架构)
- 镜像内容不可修改(只读)

每个run都是一层

- docker容器
镜像(Image)和容器(Container)有紧密的关系,镜像是静态的定义,容器是镜像运行时的实体。
容器可以被创建、启动、停正、删除、暂停等。
Docker镜像都是只读的。容器是在原来的镜像上新建了一个可读写层到原本镜像的顶部,这一层我们叫作容器层,容器层之下的叫作镜像层。
容器层的生存周期和容器一样,容器消亡时,容器层也随之消亡。容器可以理解为一个或一组相互依赖的服务。

- docker仓库
docker使用仓库(或者叫注册中心 Registry)来保存用户构建的镜像,仓库可分为公共仓库和私有仓库,公共仓库提供公开服务允许用户免费上传、下载公开的镜像,官方的Docker Hub(https://hub.docker.com),提供公共仓库服务。此仓库拥有大量的高质量的官方镜像。
除了使用公共仓库外,用户还可以在本地搭建私有仓库,比如,VMWare Harbor、gitlab 这些第三方私钥仓库软件。

- 镜像、容器和仓库之间的关系

使用Dockerfile脚本构建镜像
什么是Dockerfile
Dockerfile是由一系列命令和参数构成的脚本,这些命令应用于基础镜像并最终创建一个新的镜像。
- 对于开发人员:可以为开发团队提供一个完全一致的开发环境:
- 对于测试人员:可以直接拿开发时所构建的镜像或者通过Dockerfile文件构建一个新的镜像开始工作
- 对于运维人员:在部署时,可以实现应用的无缝移植。
常用命令及其结构
# 指定基础镜像
FROM ubuntu:20.04
# 维护者信息
LABEL maintainer="yourname@example.com"
# 设置环境变量
ENV APP_HOME /app
# 设置工作目录
WORKDIR $APP_HOME
# 复制宿主机文件到容器内
COPY app.py /app/
# 在容器内执行命令
# 安装依赖
RUN apt-get update && \
apt-get install -y python3-pip && \
pip install -r requirements.txt
# 暴露端口
EXPOSE 8000
# 启动命令
CMD ["python3", "app.py"]
常用指令详解
- RUN - 执行命令
每RUN一次都是一层,合并多个命令减少镜像层:
RUN apt-get update && \
apt-get install -y git && \
rm -rf /var/lib/apt/lists/*
- COPY vs ADD
ADD source_dir/file dest_dir/file
# 将宿主机的文件复制到容器内,支持自动解压和远程URL。如果是一个压缩文件,将会在复制后自动解压(不推荐)
COPY source_dir/file dest_dir/file
# 和ADD相似,但是如果有压缩文件并不能解压
-
CMD 与 ENTRYPOINT
CMD提供默认执行命令,可被运行时参数覆盖ENTRYPOINT配置容器启动命令
-
多阶段构建
# 构建阶段
FROM golang:1.18 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp
最终阶段
FROM alpine:latest
COPY --from=builder /app/myapp /
CMD ["/myapp"]
最佳实践
- 使用
.dockerignore文件排除不需要的文件 - 选择合适的基础镜像(Alpine版本更小巧)
- 按依赖变更频率排序指令(把变化少的层放前面)
- 单个应用对应单个容器
dockerfiler构建jdk1.8
- 准备jdk和dockerfile
[root@192 jdk_docker]# ll
总用量 190428
-rw-r--r--. 1 root root 172 2月 27 16:42 dockerfile
-rw-r--r--. 1 root root 194990602 2月 27 16:38 jdk-8u211-linux-x64.tar.gz
[root@192 jdk_docker]# cat dockerfile
FROM centos:7
WORKDIR /usr
RUN mkdir /usr/local/java
add jdk-8u211-linux-x64.tar.gz /usr/local/java
ENV JAVA_HOME /usr/local/java/jdk1.8.0_211
ENV PATH $JAVA_HOME/bin:$PATH
- 编译镜像
[root@192 jdk_docker]# docker build --no-cache -t 'jdk1.8_211:jdk1.8_211' . # 镜像名:标签
[+] Building 5.6s (9/9) FINISHED docker:default
=> [internal] load build definition from dockerfile 0.0s
=> => transferring dockerfile: 271B 0.0s
=> [internal] load metadata for docker.io/library/centos:7 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [1/4] FROM docker.io/library/centos:7 0.0s
=> [internal] load build context 1.1s
=> => transferring context: 195.03MB 1.1s
=> CACHED [2/4] WORKDIR /usr 0.0s
=> [3/4] RUN mkdir /usr/local/java 0.3s
=> [4/4] ADD jdk-8u211-linux-x64.tar.gz /usr/local/java 3.0s
=> exporting to image 1.5s
=> => exporting layers 1.5s
=> => writing image sha256:74965283e924cc32ea5aee9d0137c9e762a0fe69545c5aabb73daebc18a21144 0.0s
=> => naming to docker.io/library/jdk1.8_211:jdk1.8_211 0.0s
[root@192 jdk_docker]#
- 查看编译的镜像
[root@192 jdk_docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
jdk1.8_211 jdk1.8_211 74965283e924 About a minute ago 610MB
centos 7 eeb6ee3f44bd 3 years ago 204MB
[root@192 jdk_docker]#
清理构建缓存
docker build --no-cache xxxx #编译时携带此选项可以在编译时,直接不使用缓存
docker builder prune #清理构建缓存
/etc/docker/daemon.json 配置自动清理
{
"builder": {
"gc": {
"enabled": true,
"defaultKeepStorage": "5GB"
}
}
}
搭建私有库
1. 搭建本地 Docker 仓库
使用 Docker 官方提供的 registry 镜像来快速搭建一个本地仓库。
[root@192 ~]# docker pull registry
Using default tag: latest
latest: Pulling from library/registry
44cf07d57ee4: Pull complete
bbbdd6c6894b: Pull complete
8e82f80af0de: Pull complete
3493bf46cdec: Pull complete
6d464ea18732: Pull complete
Digest: sha256:a3d8aaa63ed8681a604f1dea0aa03f100d5895b6a58ace528858a7b332415373
Status: Downloaded newer image for registry:latest
docker.io/library/registry:latest
[root@192 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
jdk1.8_211 jdk1.8_211 74965283e924 11 minutes ago 610MB
registry latest 26b2eb03618e 17 months ago 25.4MB
[root@192 ~]# docker run -d -p 5000:5000 --restart=always --name registry registry:2
9861e17f8373c559048e55f6f1267415bf4dec4fb5fc4a7a34c2a4491f302dee
[root@192 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9861e17f8373 registry "/entrypoint.sh /etc…" 6 minutes ago Up 6 minutes 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp registry
[root@192 ~]# docker stop 9861e17f8373
9861e17f8373
[root@192 ~]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9861e17f8373 registry "/entrypoint.sh /etc…" 9 minutes ago Exited (2) 2 minutes ago registry
[root@192 ~]# docker start 9861e17f8373
9861e17f8373
[root@192 ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9861e17f8373 registry "/entrypoint.sh /etc…" 13 minutes ago Up 3 minutes 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp registry
执行以下命令,可以验证本地仓库是否创建成功(用浏览器访问也可以)
curl http://localhost:5000/v2/_catalog
返回 {"repositories":[]}代表仓库启动成功并且为空。
2. 配置 Docker客户端 以允许访问不安全仓库
由于本地仓库通常没有使用 HTTPS,所以 Docker 默认会认为它是不安全的。你需要配置 Docker 以允许访问本地不安全仓库。编辑 /etc/docker/daemon.json 文件(如果文件不存在则创建它),添加insecure-registries项,并配上私有库的IP:
[root@192 ~]# vim /etc/docker/daemon.json
{
"dns": ["8.8.8.8", "8.8.4.4"],
"registry-mirrors": ["https://registry.docker-cn.com"],
"insecure-registries": ["192.168.27.140:5000"] # 由于这里是同机部署的,也可以写成 localhost:5000
}
[root@192 ~]# systemctl restart docker # 重启docker以重新加载配置
3. 标记本地镜像
在推送镜像之前,你需要将本地的镜像标记为符合本地仓库地址的格式。
[root@192 jdk_docker]# docker push 192.168.27.140:5000/jdk1.8_211:jdk1.8_211
The push refers to repository [192.168.27.140:5000/jdk1.8_211]
An image does not exist locally with the tag: 192.168.27.140:5000/jdk1.8_211
[root@192 jdk_docker]# docker tag jdk1.8_211:jdk1.8_211 192.168.27.140:5000/jdk1.8_211:jdk1.8_211 # 标记本地镜像
[root@192 jdk_docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
192.168.27.140:5000/jdk1.8_211 jdk1.8_211 74965283e924 8 minutes ago 610MB
jdk1.8_211 jdk1.8_211 74965283e924 8 minutes ago 610MB
registry latest 26b2eb03618e 17 months ago 25.4MB
4. 使用 docker push 推送镜像
完成上述步骤后,就可以使用 docker push 命令将标记好的镜像推送到本地仓库了。
docker push localhost:5000/<本地镜像名称>:<标签>
[root@192 jdk_docker]# docker push 192.168.27.140:5000/jdk1.8_211:jdk1.8_211 # push已经标记的本地镜像
The push refers to repository [192.168.27.140:5000/jdk1.8_211]
f63d5d06f373: Pushed
afe900e2b1d3: Pushed
5f70bf18a086: Mounted from redis
174f56854903: Pushed
jdk1.8_211: digest: sha256:fa65a5d66040587a09ee6fd3271cb6a2d3a8efdd8c0cfe22a35c8888076517ea size: 1155
[root@192 jdk_docker]#
5. 验证镜像是否成功推送
[root@192 jdk_docker]# curl http://localhost:5000/v2/_catalog # 查看本地仓库中的镜像列表
{"repositories":["jdk1.8_211"]}
[root@192 jdk_docker]# curl http://localhost:5000/v2/jdk1.8_211/tags/list # 查看某个镜像的具体标签
{"name":"jdk1.8_211","tags":["jdk1.8_211"]}
[root@192 jdk_docker]#
也可以用浏览器访问。
使用docker镜像和容器的命令
镜像相关命令
docker images # 查看镜像
REPOSITORY:镜像名称
TAG:镜像标签
IMAGE ID:镜像ID
CREATED:镜像的创建日期(不是获取该镜像的日期)
SIZE:镜像大小
docker search 镜像名称 # 搜索镜像
NAME:仓库名称
DESCRIPTION:镜像描述
STARS:用户评价,反应一个镜像的受欢迎程度
OFFICIAL:是否官方
AUTOMATED:自动构建,表示该镜像由Docker Hub自动构建流程创建的
docker pull 镜像名称 # 拉取镜像
docker pull [选项] [Docker Registry地址[:端口号]/]仓库名[:标签]
docker rmi 镜像ID或镜像名称 # 删除镜像
docker rmi 'docker images -q' # 删除所有镜像
容器相关命令
创建并启动容器
docker run 是 Docker 中最常用的命令之一,用于创建并启动容器。
Docker运行容器前需要本地存在对应的镜像,如果本地不存在该镜像,Docker会自动从镜像仓库下载该镜像。
docker run [选项] 镜像 [命令] [参数]
常用参数:
-
-e KEY=VALUE设置环境变量 -
--name指定容器名称(--name 容器名或者--name=容器名都行) -
--rm容器退出时自动删除容器及所有关联存储(包括匿名卷) -
--restart always:自动重启策略 -
--privileged- 含义: 赋予容器特权,允许访问宿主机的设备。
- 使用场景: 需要更高权限的操作,如挂载设备。
- 示例:
docker run --privileged myapp
-
-v 宿主机路径:容器内路径:存储路径映射支持命名卷和路径挂载 -
-P与-p- 当使用
-P时,Docker会随机映射一个端口到内部容器开放的网络端口。 - 使用
-p时,可以指定要映射的端口-p 主机端口:容器端口
- 当使用
-
-d与-i、t-d后台运行容器,启动后不占用当前终端,适合生产环境或长期运行的服务,如 Web 服务器、数据库等。-i是--interactive的缩写,用于保持标准输入流(STDIN)开放,允许用户与容器进行交互。-t:分配一个伪tty,需与-i联用才有效

# 守护式创建容器
# docker run -d --name=容器名称 镜像名称:标签
# docker run -d nginx
# 交互式创建容器
echo "Hello" | docker run -i myapp process_data
docker run -i myapp < input.txt
docker run -it --name=容器名称 镜像名称:标签 /bin/bash
docker run -it --name=my_ubuntu ubuntu:20.04 bash
docker run -itd --name=容器名称 镜像名称:标签 /bin/bash
使用 `docker attach mycontainer` 或者 `docker exec -it mycontainer bash` 进入容器的交互式 shell
退出容器exit
注意:
如果你只使用 -d 而不加 -i,则无法通过 docker attach 进入该容器的标准输入。
如果你只使用 -i 而不加 -t,可能会提示 the input device is not a TTY 错误。
推荐组合使用:-itd 可以让你既以后台方式运行容器,又能交互式访问。
容器的启动与删除
docker start [容器名/ID] # 启动容器
docker stop [容器名/ID] # 停止容器
docker restart [容器名/ID] # 重启容器
docker rm [容器名称/ID] # 删除容器
查看容器的信息
docker ps # 查看正在运行的容器
docker ps -a # 查看所有容器
docker ps -l # 查看最后一次运行的容器
docker ps -f status=exited # 查看停止的容器
docker logs [容器] # 查看容器日志
docker logs -f web-server # 跟踪实时日志
docker logs --tail=100 web-server # 显示最后100行日志
docker logs web-server 2>&1 | grep ERROR # 过滤包含ERROR的日志
docker inspect [容器/镜像] # 查看容器运行的各种参数
docker inspect --format='{{.NetworkSettings.IPAddress}}' 容器名称(容器ID) # 直接输出IP地址
docker inspect --format '{{.GraphDriver.Data.MergedDir}}' 容器名称(容器ID) # 获取容器存储目录
docker exec -it [容器] bash # 进入正在运行的容器中执行命令
docker cp 需要拷贝的文件或目录 容器名称:容器目录 # 将文件拷到容器中
docker cp 容器名称:容器目录 需要拷贝的文件或目录 # 将文件从容器中拷出来
docker container ls -l # 查看容器信息
docker port 容器ID # 查看指定容器的端口映射信息
其他常用命令
docker version # 查看docker版本
docker info # 查看docker配置信息
docker stats # 查看实时资源使用
docker top web-server # 查看进程信息
迁移与备份
[root@192 jdk_docker]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9861e17f8373 registry "/entrypoint.sh /etc…" 6 hours ago Up 6 hours 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp registry
[root@192 jdk_docker]# docker stop 9861e17f8373
9861e17f8373
[root@192 jdk_docker]# docker commit registry myregistry # 将容器保存为镜像
sha256:7fed2f91278384defb83786ddcba0fa9a91f19919550ae810aa77ee404978ecb
[root@192 jdk_docker]# docker save -o myregistry.tar myregistry # 将镜像保存为文件(还要备份原数据卷)
[root@192 jdk_docker]# ll
总用量 215848
-rw-r--r--. 1 root root 172 2月 27 16:42 dockerfile
-rw-r--r--. 1 root root 194990602 2月 27 16:38 jdk-8u211-linux-x64.tar.gz
-rw-------. 1 root root 26027520 2月 27 17:54 myregistry.tar
[root@192 jdk_docker]#
[root@192 jdk_docker]# docker rm 9861e17f8373 # 这里先删除本地的容器和镜像
9861e17f8373
[root@192 jdk_docker]# docker rmi myregistry
Untagged: myregistry:latest
Deleted: sha256:7fed2f91278384defb83786ddcba0fa9a91f19919550ae810aa77ee404978ecb
Deleted: sha256:9cddfb42466557440b7e04bfa829e94ca5c825582a4650de2a50a51c6af055b0
[root@192 jdk_docker]# docker load -i myregistry.tar # 导入镜像
efe8785349cb: Loading layer [==================================================>] 2.56kB/2.56kB
Loaded image: myregistry:latest
[root@192 jdk_docker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
myregistry latest 7fed2f912783 3 minutes ago 25.4MB
192.168.27.140:5000/jdk1.8_21144 jdk1.8_21133 74965283e924 38 minutes ago 610MB
192.168.27.140:5000/jdk1.8_211 jdk1.8_211 74965283e924 38 minutes ago 610MB
192.168.27.140:5000/jdk1.8_211 jdk1.8_21133 74965283e924 38 minutes ago 610MB
jdk1.8_211 jdk1.8_211 74965283e924 38 minutes ago 610MB
registry latest 26b2eb03618e 17 months ago 25.4MB
centos 7 eeb6ee3f44bd 3 years ago 204MB
[root@192 jdk_docker]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@localhost ~]# docker run -d -p 5000:5000 --restart always --name registry myregistry
40ab2e3f3ca45b88c9cc1901db54c7b3ce07c3810c602952d1a9d7caa7345e79
[root@localhost ~]#
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
40ab2e3f3ca4 myregistry "/entrypoint.sh /etc…" 8 seconds ago Up 8 seconds 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp registry
[root@localhost ~]# curl http://localhost:5000/v2/_catalog
{"repositories":[]}
[root@localhost ~]#
docker可视化管理工具
portainer

docker run -d -p 9000:9000 --name portainer --restart always -v /var/run/docker.sock:/var/run/docker.sock \
-v portainer_data:/data swr.cn-north-1.myhuaweicloud.com/iivey/portainer-ce:2.19.1
-v /data/portainer/public:/public
[root@192 ~]# docker pull portainer/portainer
Using default tag: latest
latest: Pulling from portainer/portainer
772227786281: Pull complete
96fd13befc87: Pull complete
0bad1d247b5b: Pull complete
b5d1b01b1d39: Pull complete
Digest: sha256:47b064434edf437badf7337e516e07f64477485c8ecc663ddabbe824b20c672d
Status: Downloaded newer image for portainer/portainer:latest
docker.io/portainer/portainer:latest
[root@192 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
apache-tomcat 8.5.32 6aaa24fb4950 About an hour ago 218MB
192.168.27.140:5000/jdk1.8_211 jdk1.8_211 74965283e924 24 hours ago 610MB
ghcr.io/open-webui/open-webui main 06e9c7ce6dbd 2 weeks ago 4.33GB
postgres 15-alpine 9e9a000b8503 2 weeks ago 273MB
nginx latest 97662d24417b 3 weeks ago 192MB
mysql latest 5568fddd4f66 5 weeks ago 797MB
mysql 8.0 6616596982ed 5 weeks ago 764MB
langgenius/dify-plugin-daemon 0.0.1-local d99b176a32cf 7 weeks ago 247MB
192.168.27.140:5000/redis 6-alpine 6dd588768b9b 7 weeks ago 30.2MB
redis 6-alpine 6dd588768b9b 7 weeks ago 30.2MB
langgenius/dify-sandbox 0.2.10 4328059557e8 4 months ago 567MB
ubuntu 20.04 6013ae1a63c2 4 months ago 72.8MB
ubuntu/squid latest 87507c4542d0 5 months ago 242MB
registry 2 26b2eb03618e 17 months ago 25.4MB
semitechnologies/weaviate 1.19.0 8ec9f084ab23 22 months ago 52.5MB
portainer/portainer latest 5f11582196a4 2 years ago 287MB
centos 7 eeb6ee3f44bd 3 years ago 204MB
[root@192 ~]# docker run -d -p 9000:9000 --name portainer --restart always -v /var/run/docker.sock:/var/run/docker.sock \
> -v portainer_data:/data portainer/portainer:latest
c31cf80e5c22ded073c4959e06be91585815b70cf2e6bcf094b7efbc5e5aadcd
[root@192 ~]#
dpanel
[root@192 ~]# docker pull dpanel/dpanel
Using default tag: latest
latest: Pulling from dpanel/dpanel
f18232174bc9: Pull complete
736b77e86606: Pull complete
d8d58e0974fa: Pull complete
46962fc14f9d: Pull complete
7f43e9c7b398: Pull complete
bc905cb07639: Pull complete
469124ee7284: Pull complete
1f21b4681787: Pull complete
4f4fb700ef54: Pull complete
Digest: sha256:274bd072888c9ab4c48c5d9c8d8c138710a996b7abc05e80d70291ed98a90535
Status: Downloaded newer image for dpanel/dpanel:latest
docker.io/dpanel/dpanel:latest
[root@192 ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
dpanel/dpanel latest f08f7b230950 2 days ago 179MB
registry 2 26b2eb03618e 17 months ago 25.4MB
portainer/portainer latest 5f11582196a4 2 years ago 287MB
uifd/ui-for-docker latest 965940f98fa5 8 years ago 8.1MB
[root@192 ~]# docker run -p 8807:8080 --name dpanel \
> -e APP_NAME=dpanel \
> -v /var/run/docker.sock:/var/run/docker.sock \
> -v /mydata/dpanel:/dpanel \
> -d dpanel/dpanel:lite
Unable to find image 'dpanel/dpanel:lite' locally
lite: Pulling from dpanel/dpanel
f18232174bc9: Already exists
3bf1601c01d5: Pull complete
f1b6edf430fd: Pull complete
5bdf60eb46c5: Pull complete
22de23157caa: Pull complete
4f4fb700ef54: Pull complete
Digest: sha256:e550b219353c1b10c022b2a08b2d48376ea752b3650de8d4a36256a85280d8f5
Status: Downloaded newer image for dpanel/dpanel:lite
35c166e2bd735b37e40598631e2332f66ac386a6f0e9f92acd4963915bfe36f8
[root@192 ~]#

浙公网安备 33010602011771号