我给自己的要求是,大概会用就好,当沙箱环境来用。
当今任何工具使用,你都可以借助ChatGPT来问答解决,包括基础的内容。
Docker基本的东西要直到,Containers、Images、Registries、Networks、Volumes、Docker Contexts
在VSCode中有插件 “Container Tools” By Microsoft 可以用,可以管理上面6类内容。
Docker是一个以一致的方式构建运行和交付应用程序的平台。 A platform for building, running and shipping applications.
虚拟机:
Windows | Linux
----------------
Hypervisor
----------------
MacHypervisors 有 VirtualBox、VMware、Hyper-v(Windows only)。
Containers优点:
Docker架构,Docker使用客户端服务器架构,因此它有一个客户端组件。
Client--REST API-->Docker EngineContainers: Process1 Process2 Process3
-----------
Windowsroot@ser745692301841:/dev_dir/avant/bin# docker version
Client:
Version: 27.5.1
API version: 1.47
Go version: go1.22.2
Git commit: 27.5.1-0ubuntu3~24.04.2
Built: Mon Jun 2 11:51:53 2025
OS/Arch: linux/amd64
Context: default
Server:
Engine:
Version: 27.5.1
API version: 1.47 (minimum version 1.24)
Go version: go1.22.2
Git commit: 27.5.1-0ubuntu3~24.04.2
Built: Mon Jun 2 11:51:53 2025
OS/Arch: linux/amd64
Experimental: false
containerd:
Version: 1.7.27
GitCommit:
runc:
Version: 1.2.5-0ubuntu1~24.04.1
GitCommit:
docker-init:
Version: 0.19.0
GitCommit: https://docs.docker.com/get-started/get-docker/
根据是哪种系统 Windows、Mac、Linux 安装 Docker。
Dockerlize,为项目写 Dockerfile。 Application+Dockerfile 打包成镜像 Image。
root@ser745692301841:/dev_dir# mkdir hello-docker
root@ser745692301841:/dev_dir# cd hello-docker
root@ser745692301841:/dev_dir/hello-docker# touch app.js
root@ser745692301841:/dev_dir/hello-docker# ls
app.js// app.js
console.log("Hello Docker!");root@ser745692301841:/dev_dir/hello-docker# node app.js
Hello Docker!流程是 * Start with an OS * Install Node * Copy app files * Run node app.js
https://hub.docker.com/_/node 使用基础镜像node,基础镜像是什么,这就有点像面向对象编程中的继承。
例如 node:alpine 在:有不同的发行版,可以向dockerhub中查看。
FROM node:alpine
# 要将当前目录中的所有文件复制到该映像的app目录中
COPY . /app
# 指定当前工作目录workdir
WORKDIR /app
# 执行命令
CMD node /app/app.js# -t 指定tag ./指定在那个文件路径下找到Dockerfile
root@ser745692301841:/dev_dir/hello-docker# ls
Dockerfile app.js
root@ser745692301841:/dev_dir/hello-docker# docker build -t hello-docker ./
Digest: sha256:77f3c4d1f33c17dfa4af4b0add57d86957187873e313c2c37f52831d117645c8
Status: Downloaded newer image for node:alpine
---> 0d3f5d817db1
Step 2/4 : COPY . /app
---> c231dc670222
Step 3/4 : WORKDIR /app
---> Running in 348cdfb75ea5
---> Removed intermediate container 348cdfb75ea5
---> 0edce7865a3b
Step 4/4 : CMD node /app/app.js
---> Running in 2c5ae4933702
---> Removed intermediate container 2c5ae4933702
---> f7f9d58fbf17
Successfully built f7f9d58fbf17
Successfully tagged hello-docker:latest
root@ser745692301841:/dev_dir/hello-docker# ls
Dockerfile app.js 还是只有Dockerfile 和 app.js, 因为这里不存储镜像,事实上,镜像不是单个文件,Docker如何存储这个镜像很很复杂,我们不必担心。
查看该计算机上的所有映像
root@ser745692301841:/dev_dir/hello-docker# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-docker latest f7f9d58fbf17 2 minutes ago 168MB
node alpine 0d3f5d817db1 5 days ago 168MB
redis latest f2cd22713a18 2 months ago 128MB
mongo latest ccf68b64aa3e 3 months ago 901MB
postgres latest 445ed93b882f 3 months ago 438MB
rabbitmq management 928da815d9a3 5 months ago 275MB
mysql latest 4c2531d6bf10 5 months ago 859MB
root@ser745692301841:/dev_dir/hello-docker# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-docker latest f7f9d58fbf17 3 minutes ago 168MB
node alpine 0d3f5d817db1 5 days ago 168MB
redis latest f2cd22713a18 2 months ago 128MB
mongo latest ccf68b64aa3e 3 months ago 901MB
postgres latest 445ed93b882f 3 months ago 438MB
rabbitmq management 928da815d9a3 5 months ago 275MB
mysql latest 4c2531d6bf10 5 months ago 859MB运行我们刚才build出的hello-docker镜像
root@ser745692301841:/dev_dir/hello-docker# docker run hello-docker
Hello Docker!查看主机上的容器
root@ser745692301841:/dev_dir/hello-docker# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
root@ser745692301841:/dev_dir/hello-docker# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0ab0ab52a140 hello-docker "docker-entrypoint.s…" 19 seconds ago Exited (0) 18 seconds ago reverent_franklin
root@ser745692301841:/dev_dir/hello-docker# docker rm 0ab0ab52a140
0ab0ab52a140
root@ser745692301841:/dev_dir/hello-docker# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES如何从dockerhub拉取镜像,例如
docker pull gaowanlu/avant就会从dockerhub拉去 镜像 https://hub.docker.com/r/gaowanlu/avant
https://hub.docker.com/_/ubuntu
root@ser745692301841:/dev_dir/note# docker run ubuntu
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
953cdd413371: Pull complete
Digest: sha256:353675e2a41babd526e2b837d7ec780c2a05bca0164f7ea5dbbd433d21d166fc
Status: Downloaded newer image for ubuntu:latest
root@ser745692301841:/dev_dir/note#
root@ser745692301841:/dev_dir/note# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b922ca594b6e ubuntu "/bin/bash" 11 seconds ago Exited (0) 10 seconds ago vigorous_herschel
root@ser745692301841:/dev_dir/note# docker rm b922ca594b6e
b922ca594b6e执行docker run ubuntu 会直接 Exit。容器会启动就停止了。
交互模式下启动容器
root@ser745692301841:/dev_dir/note# docker run -it ubuntu
root@b704966c4897:/#
root@b704966c4897:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@b704966c4897:/# exit
exit
root@ser745692301841:/dev_dir/note# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b704966c4897 ubuntu "/bin/bash" 15 seconds ago Exited (0) 5 seconds ago angry_jones会Linux命令行,学习Linux基本知识,是你学习使用docker的前提。
可以用 docker start
root@ser745692301841:/dev_dir/note# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
root@ser745692301841:/dev_dir/note# docker run hello-docker
Hello Docker!
root@ser745692301841:/dev_dir/note# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1d01b9630803 hello-docker "docker-entrypoint.s…" 5 seconds ago Exited (0) 3 seconds ago charming_williams
root@ser745692301841:/dev_dir/note# docker start -i 1d01b9630803
Hello Docker!
root@ser745692301841:/dev_dir/note# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1d01b9630803 hello-docker "docker-entrypoint.s…" 18 seconds ago Exited (0) 4 seconds ago charming_williams
root@ser745692301841:/dev_dir/note# 进入正在运行的容器的bash
docker exec -it 容器ID bashroot@ser745692301841:/dev_dir/note# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
hello-docker latest f7f9d58fbf17 4 hours ago 168MB
node alpine 0d3f5d817db1 5 days ago 168MB
ubuntu latest 6d79abd4c962 3 weeks ago 78.1MB
redis latest f2cd22713a18 2 months ago 128MB
mongo latest ccf68b64aa3e 3 months ago 901MB
postgres latest 445ed93b882f 3 months ago 438MB
rabbitmq management 928da815d9a3 5 months ago 275MB
mysql latest 4c2531d6bf10 5 months ago 859MB
root@ser745692301841:/dev_dir/note# docker run -it ubuntu
root@7eb976bab217:/#
root@ser745692301841:/dev_dir/note# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
7eb976bab217 ubuntu "/bin/bash" 20 seconds ago Up 19 seconds jolly_mclaren
root@ser745692301841:/dev_dir/note# docker exec 7eb976bab217 bash
root@ser745692301841:/dev_dir/note# docker exec -it 7eb976bab217 bash
root@7eb976bab217:/# ls
bin dev home lib64 mnt proc run srv tmp var
boot etc lib media opt root sbin sys usr
root@7eb976bab217:/# 它们的关系就像 面向对象编程中的 Class 与 Class的对象实例,Image是Class,Container是Object。
https://github.com/mfavant/avant
其是一个C++ CMake Linux 项目。
在项目下建立一个Dockerfile
生产环境项目中,永远不要使用latest,因为ubuntu官方发布了新的image,我们每次构建时可能都与以前的镜像不同。
root@ser745692301841:/dev_dir/dockerlab# ls
root@ser745692301841:/dev_dir/dockerlab# git clone https://github.com/mfavant/avant.git
Cloning into 'avant'...
remote: Enumerating objects: 1956, done.
remote: Counting objects: 100% (149/149), done.
remote: Compressing objects: 100% (23/23), done.
remote: Total 1956 (delta 136), reused 132 (delta 126), pack-reused 1807 (from 1)
Receiving objects: 100% (1956/1956), 1.37 MiB | 2.44 MiB/s, done.
Resolving deltas: 100% (1175/1175), done.
root@ser745692301841:/dev_dir/dockerlab# ls
avant
root@ser745692301841:/dev_dir/dockerlab# cd avant
root@ser745692301841:/dev_dir/dockerlab/avant# rm Dockerfile
root@ser745692301841:/dev_dir/dockerlab/avant# touch Dockerfile# 使用最新版本的ubuntu
FROM ubuntu:25.04构建镜像 docker-avant
root@ser745692301841:/dev_dir/dockerlab/avant# docker build -t docker-avant ./
DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
Install the buildx component to build images with BuildKit:
https://docs.docker.com/go/buildx/
Sending build context to Docker daemon 5.009MB
Step 1/1 : FROM ubuntu:25.04
25.04: Pulling from library/ubuntu
bf2a53a9f660: Pull complete
Digest: sha256:103c7471649a4fd9996fe73dff20f46082e4e0f0f6240c91954b8b09c38b6faf
Status: Downloaded newer image for ubuntu:25.04
---> 482b635a13cd
Successfully built 482b635a13cd
Successfully tagged docker-avant:latest
root@ser745692301841:/dev_dir/dockerlab/avant# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
node alpine 0d3f5d817db1 7 days ago 168MB
docker-avant latest 482b635a13cd 7 days ago 77MB
ubuntu 25.04 482b635a13cd 7 days ago 77MB
ubuntu latest 6d79abd4c962 3 weeks ago 78.1MB
redis latest f2cd22713a18 2 months ago 128MB
mongo latest ccf68b64aa3e 3 months ago 901MB
postgres latest 445ed93b882f 3 months ago 438MB
rabbitmq management 928da815d9a3 5 months ago 275MB
mysql latest 4c2531d6bf10 5 months ago 859MB交互模式启动镜像 docker-avant
root@ser745692301841:/dev_dir/dockerlab/avant# docker run -it docker-avant
root@a8516f0e9781:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@a8516f0e9781:/# 只是进入了一个 ubuntu:25.04环境,并不能找到avant相关项目信息,因为我们dockerfile中还没有涉及到呢。
FROM ubuntu:25.04
WORKDIR /avant
COPY ./ ./build镜像
root@ser745692301841:/dev_dir/dockerlab/avant# docker build -t docker-avant ./
DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
Install the buildx component to build images with BuildKit:
https://docs.docker.com/go/buildx/
Sending build context to Docker daemon 5.009MB
Step 1/3 : FROM ubuntu:25.04
---> 482b635a13cd
Step 2/3 : WORKDIR /avant
---> Running in a6e24d55fc73
---> Removed intermediate container a6e24d55fc73
---> e26cffc594c9
Step 3/3 : COPY ./ ./
---> 65090793a7f1
Successfully built 65090793a7f1
Successfully tagged docker-avant:latest
root@ser745692301841:/dev_dir/dockerlab/avant# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-avant latest 65090793a7f1 9 seconds ago 81.7MB
node alpine 0d3f5d817db1 7 days ago 168MB
ubuntu 25.04 482b635a13cd 7 days ago 77MB
redis latest f2cd22713a18 2 months ago 128MB
mongo latest ccf68b64aa3e 3 months ago 901MB
postgres latest 445ed93b882f 3 months ago 438MB
rabbitmq management 928da815d9a3 5 months ago 275MB
mysql latest 4c2531d6bf10 5 months ago 859MB
root@ser745692301841:/dev_dir/dockerlab/avant# 启动镜像docker-avant容器
root@ser745692301841:/dev_dir/dockerlab/avant# docker run -it docker-avant
root@be893c402dbf:/avant# ls
CMakeLists.txt Dockerfile LICENSE README.md bin centos8.md client external protobuf.md protocol src test
root@be893c402dbf:/avant# cd ..
root@be893c402dbf:/# ls
avant bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@be893c402dbf:/# cd avant
root@be893c402dbf:/avant# ls
CMakeLists.txt Dockerfile LICENSE README.md bin centos8.md client external protobuf.md protocol src test
root@be893c402dbf:/avant# 可见我们的项目内容已经被COPY到镜像中的 /avant目录下了。
# COPY 多个文件
COPY 文件1 文件2 /avant/
# ADD可以创建文件夹
ADD /新文件夹
# ADD可以网络下载文件到目标文件夹
ADD http://file /目标文件夹/
# ADD可以解压到目标文件夹
ADD 压缩文件.zip /目标文件夹/类似于git中的 .gitignore, 我们不希望项目中的某些内容被COPY到镜像中。例如nodejs项目中的 node_modules文件夹。
bin/avant
build/
.git/
root@ser745692301841:/dev_dir/dockerlab/avant# docker build -t docker-avant ./
DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
Install the buildx component to build images with BuildKit:
https://docs.docker.com/go/buildx/
Sending build context to Docker daemon 3.417MB
Step 1/3 : FROM ubuntu:25.04
---> 482b635a13cd
Step 2/3 : WORKDIR /avant
---> Running in 731ce162db64
---> Removed intermediate container 731ce162db64
---> df59f482154d
Step 3/3 : COPY ./ ./
---> 8439d5ece311
Successfully built 8439d5ece311
Successfully tagged docker-avant:latest
root@ser745692301841:/dev_dir/dockerlab/avant# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-avant latest 8439d5ece311 7 seconds ago 80.2MB
node alpine 0d3f5d817db1 7 days ago 168MB
ubuntu 25.04 482b635a13cd 7 days ago 77MB
redis latest f2cd22713a18 2 months ago 128MB
mongo latest ccf68b64aa3e 3 months ago 901MB
postgres latest 445ed93b882f 3 months ago 438MB
rabbitmq management 928da815d9a3 5 months ago 275MB
mysql latest 4c2531d6bf10 5 months ago 859MB
root@ser745692301841:/dev_dir/dockerlab/avant# 下一步是安装我们的项目依赖项
FROM ubuntu:25.04
WORKDIR /avant
COPY ./ ./
RUN apt update
RUN apt install cmake g++ make git -y
RUN apt install protobuf-compiler libprotobuf-dev -y
RUN apt install libssl-dev -ydocker build -t docker-avant ./RUN提供的命令行将会一条条执行,然后镜像中就会有我们配置的项目环境。
我们运行一个容器。
root@ser745692301841:/dev_dir/dockerlab/avant# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-avant latest 5a78ee94b4ce 3 seconds ago 579MB可见镜像挺大的。
root@ser745692301841:/dev_dir/dockerlab/avant# docker run -it docker-avant
root@d31b5733a6ae:/avant# ls
CMakeLists.txt Dockerfile LICENSE README.md bin centos8.md client external protobuf.md protocol src test
root@d31b5733a6ae:/avant# mkdir build
root@d31b5733a6ae:/avant# cd ./protocol
root@d31b5733a6ae:/avant/protocol# make
root@d31b5733a6ae:/avant/protocol# cd ../
root@d31b5733a6ae:/avant# mkdir build
root@d31b5733a6ae:/avant# cd build
root@d31b5733a6ae:/avant/build# cmake ../
-- The C compiler identification is GNU 14.2.0
-- The CXX compiler identification is GNU 14.2.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
/avant/src
external start
external end
-- Configuring done (0.8s)
-- Generating done (0.1s)
-- Build files have been written to: /avant/build
root@d31b5733a6ae:/avant/build# make -j2
[ 1%] Building CXX object external/CMakeFiles/avant-buffer.dir/avant-buffer/buffer.cpp.o
[ 2%] Building CXX object external/CMakeFiles/avant-xml.dir/avant-xml/document.cpp.o
[ 3%] Linking CXX shared library libavant-buffer.so
[ 3%] Built target avant-buffer
[ 4%] Building C object external/CMakeFiles/avant-lua.dir/lua/lapi.c.o
[ 5%] Building C object external/CMakeFiles/avant-lua.dir/lua/lauxlib.c.o
...
[ 99%] Building CXX object CMakeFiles/avant.dir/protocol/proto_res/proto_tunnel.pb.cc.o
[100%] Linking CXX executable /avant/bin/avant
[100%] Built target avant
root@d31b5733a6ae:/avant/build# cd ../bin
root@d31b5733a6ae:/avant/bin# ls
avant config lua我们成功构建出了项目的可执行文件。
FROM ubuntu:25.04
WORKDIR /avant
COPY ./ ./
RUN apt update
RUN apt install cmake g++ make git -y
RUN apt install protobuf-compiler libprotobuf-dev -y
RUN apt install libssl-dev -y
ENV AVANT_LISTEN_PORT=20023启动一个容器
root@ser745692301841:/dev_dir/dockerlab/avant# docker run -it docker-avant
root@adb1cdb66bed:/avant# printenv
HOSTNAME=adb1cdb66bed
PWD=/avant
AVANT_LISTEN_PORT=20023
HOME=/root
...
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
_=/usr/bin/printenv
root@adb1cdb66bed:/avant# printenv AVANT_LISTEN_PORT
20023
root@adb1cdb66bed:/avant# echo $AVANT_LISTEN_PORT
20023这么一来我们可以将项目构建命令写进Dockerfile
FROM ubuntu:25.04
WORKDIR /avant
COPY ./ ./
RUN apt update
RUN apt install cmake g++ make git -y
RUN apt install protobuf-compiler libprotobuf-dev -y
RUN apt install libssl-dev -y
WORKDIR /avant
RUN rm -rf CMakeCache.txt \
&& cd protocol \
&& make \
&& cd .. \
&& mkdir build \
&& rm -rf ./build/* \
&& cd build \
&& cmake .. \
&& make -j3 \
&& cd .. \
&& cd bin \
&& ls
WORKDIR /avant/bin在 Dockerfile中 使用EXPOSE 声明端口是个好习惯,这仅仅是像文档一样告诉别人 启动的容器需要暴露哪些端口。
FROM ubuntu:25.04
WORKDIR /avant
COPY ./ ./
RUN apt update
RUN apt install cmake g++ make git -y
RUN apt install protobuf-compiler libprotobuf-dev -y
RUN apt install libssl-dev -y
WORKDIR /avant
RUN rm -rf CMakeCache.txt \
&& cd protocol \
&& make \
&& cd .. \
&& mkdir build \
&& rm -rf ./build/* \
&& cd build \
&& cmake .. \
&& make -j3 \
&& cd .. \
&& cd bin \
&& ls
WORKDIR /avant/bin
EXPOSE 20023 20024main.ini 为avant配置文件,公网监听端口为20023、IPC通信端口为20024。
root@adb1cdb66bed:/avant/bin# ls
config lua
root@adb1cdb66bed:/avant/bin# cd config
root@adb1cdb66bed:/avant/bin/config# ls
ipc.json main.ini ssl_cfg.sh workflow.xml
root@adb1cdb66bed:/avant/bin/config# cat main.ini
[server]
app_id = 0.0.0.1
ip = 0.0.0.0
port = 20023
# worker_cnt range [1, 511]
worker_cnt = 4
# max_client_cnt range [1, 8388607]
max_client_cnt = 20000
# using wait_time setting tick time, 10ms
epoll_wait_time = 100
accept_per_tick = 100
task_type = HTTP_TASK
#task_type = STREAM_TASK
#task_type = WEBSOCKET_TASK
http_static_dir = /avant_static
lua_dir = ./lua
# SSL_CTX_use_certificate_chain_file
crt.pem = ./config/certificate.crt
# SSL_CTX_use_PrivateKey_file
key.pem = ./config/private_key.pem
use_ssl = 0
daemon = 1
# DEBUG 0, INFO 1, WARN 2, ERROR 3, FATAL 4,
log_level = 0
[ipc]
max_ipc_conn_num = 100
ipc_json_path = ./config/ipc.json
[client]
threads = 10
root@adb1cdb66bed:/avant/bin/config# cat ipc.json
[
{
"app_id": "0.0.0.1",
"ip": "127.0.0.1",
"port": 20024
}
]
root@adb1cdb66bed:/avant/bin/config# 默认情况下 docker使用具有最高权限的root用户运行我们的应用程序。
# 建立组
root@767e336bc8e9:/# groupadd app
# 建立用户并加入组
root@767e336bc8e9:/# useradd -r -g app -s /usr/sbin/nologin app
# 查看用户属于哪些组
root@767e336bc8e9:/# groups app
app : app
# 另一种更简洁的 Ubuntu 写法
adduser --system --ingroup app appFROM ubuntu:25.04
WORKDIR /avant
COPY ./ ./
RUN apt update
RUN apt install cmake g++ make git -y
RUN apt install protobuf-compiler libprotobuf-dev -y
RUN apt install libssl-dev -y
EXPOSE 20023 20024
RUN groupadd app && useradd -r -g app -s /usr/sbin/nologin app
USER app
WORKDIR /avant
RUN rm -rf CMakeCache.txt \
&& cd protocol \
&& make \
&& cd .. \
&& mkdir build \
&& rm -rf ./build/* \
&& cd build \
&& cmake .. \
&& make -j3 \
&& cd .. \
&& cd bin \
&& ls
WORKDIR /avant/binroot@ser745692301841:/dev_dir/dockerlab/avant# docker build -t docker-avant ./会构建失败,因为 COPY项目时是用 root用户执行的,然后 构架项目用的app用户,app用户没有某些项目文件权限。
改一下Dockerfile
FROM ubuntu:25.04
RUN apt update
RUN apt install cmake g++ make git -y
RUN apt install protobuf-compiler libprotobuf-dev -y
RUN apt install libssl-dev -y
RUN groupadd app && useradd -r -g app -s /usr/sbin/nologin app
WORKDIR /avant
COPY ./ ./
RUN rm -rf CMakeCache.txt \
&& cd protocol \
&& make \
&& cd .. \
&& mkdir build \
&& rm -rf ./build/* \
&& cd build \
&& cmake .. \
&& make -j3 \
&& cd .. \
&& cd bin \
&& ls
WORKDIR /avant/bin
EXPOSE 20023 20024
USER app为了方便我们还是直接使用 root, 因为COPY 的动作是用 root执行的,再此我们不关心用户问题了。
FROM ubuntu:25.04
RUN apt update
RUN apt install cmake g++ make git -y
RUN apt install protobuf-compiler libprotobuf-dev -y
RUN apt install libssl-dev -y
WORKDIR /avant
COPY ./ ./
RUN rm -rf CMakeCache.txt \
&& cd protocol \
&& make \
&& cd .. \
&& mkdir build \
&& rm -rf ./build/* \
&& cd build \
&& cmake .. \
&& make -j3 \
&& cd .. \
&& cd bin \
&& ls
WORKDIR /avant/bin
EXPOSE 20023 20024docker build -t docker-avant ./# 启动容器
root@ser745692301841:/dev_dir/dockerlab/avant# docker run docker-avant ./avant
loading file sucess: /avant/bin/config/main.ini执行了 /avant/bin 下的 avant可执行文件 avant配置文件 main.ini daemon = 1 制定了 avant为守护进程运行。
root@ser745692301841:/dev_dir/dockerlab/avant/bin# ls
config lua
root@ser745692301841:/dev_dir/dockerlab/avant/bin# cat config/main.ini
[server]
app_id = 0.0.0.1
ip = 0.0.0.0
port = 20023
# worker_cnt range [1, 511]
worker_cnt = 4
# max_client_cnt range [1, 8388607]
max_client_cnt = 20000
# using wait_time setting tick time, 10ms
epoll_wait_time = 100
accept_per_tick = 100
task_type = HTTP_TASK
#task_type = STREAM_TASK
#task_type = WEBSOCKET_TASK
http_static_dir = /avant_static
lua_dir = ./lua
# SSL_CTX_use_certificate_chain_file
crt.pem = ./config/certificate.crt
# SSL_CTX_use_PrivateKey_file
key.pem = ./config/private_key.pem
use_ssl = 0
daemon = 1
# DEBUG 0, INFO 1, WARN 2, ERROR 3, FATAL 4,
log_level = 0
[ipc]
max_ipc_conn_num = 100
ipc_json_path = ./config/ipc.json
[client]关于 RUN 与 CMD,RUN是构建时指令,构建镜像时的运行命令。
CMD 是在得到镜像后,启动容器执行的命令。
# Shell form
# CMD ./avant
# Exec form
CMD ["avant"]
ENTRYPOINT [ "avant" ]例如nodejs项目
CMD ["npm", "start"]
ENTRYPOINT ["npm", "start"]CMD 与 ENTRYPOINT 有何不同,CMD可以轻易的被覆盖
docker run react-app sh
# 此处的sh 会把 CMD ["npm", "start"] 覆盖掉
# 而使用ENTRYPOINT 就不能 必须指定 --entrypoint才行
docker run react-app --entrypoint 你的命令我们发现每次build都会花费很长时间,这是因为 我们配置环境花费了大量时间。在 apt install 时。
这是可以优化的,Image中是有层级的,你可以理解为层级就是只有配置文件的操作系统。
root@ser745692301841:/dev_dir/dockerlab/avant# docker history docker-avant
IMAGE CREATED CREATED BY SIZE COMMENT
ae7b5f04f085 45 seconds ago /bin/sh -c #(nop) EXPOSE 20023 20024 0B
d4c5825849a5 45 seconds ago /bin/sh -c #(nop) WORKDIR /avant/bin 0B
5545133ce33e 46 seconds ago /bin/sh -c rm -rf CMakeCache.txt && cd p… 70.6MB
59094d39a6c5 About a minute ago /bin/sh -c #(nop) COPY dir:27c02cd54de056900… 3.14MB
1c44fb52b068 About a minute ago /bin/sh -c #(nop) WORKDIR /avant 0B
89e1cc658d0d About a minute ago /bin/sh -c apt install libssl-dev -y 16.7MB
c8365f8a1bb3 About a minute ago /bin/sh -c apt install protobuf-compiler lib… 20.7MB
f4f7a3fa69d7 2 minutes ago /bin/sh -c apt install cmake g++ make git -y 421MB
2e2b66762d70 3 minutes ago /bin/sh -c apt update 40.2MB
482b635a13cd 8 days ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 8 days ago /bin/sh -c #(nop) ADD file:286c37c491e2efd33… 77MB
<missing> 8 days ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B
<missing> 8 days ago /bin/sh -c #(nop) LABEL org.opencontainers.… 0B
<missing> 8 days ago /bin/sh -c #(nop) ARG LAUNCHPAD_BUILD_ARCH 0B
<missing> 8 days ago /bin/sh -c #(nop) ARG RELEASE 0B docker有一种自我优化的内在机制,当我们每次让docker去创建映像,它会观察第一个命令,看看命令改变了没有,如果没有 变化它就不会重构映像,它会从缓存中复用,然后看第二条重复检查变化,而COPY 比较特殊,docker看不出是否发生了变化, 这样它就需要去看具体文件内容,也就是说,当你在应用中进行微笑改动,docker就无法使用它的缓存,COPY之后的所有层级都要进行重构。
例如nodejs项目
FROM node:14.16.0-alpine3.13
WORKDIR /app
COPY . .
RUN npm install
ENV API_URL=http://api.myapp.com/
EXPOSE 3000
CMD ["npm", "start"]这样每次build,都会重新 npm install。
可以优化为
FROM node:14.16.0-alpine3.13
WORKDIR /app
COPY package*.json .
RUN npm install
COPY . .
ENV API_URL=http://api.myapp.com/
EXPOSE 3000
CMD ["npm", "start"]这样就不会每次都要从网络上拉取npm包。
如何清空缓存呢。
清空全部镜像缓存
# 不管在哪个目录下都能执行
docker builder prune -af如果你只是想重建某个项目,不想全局清理,可以用:
docker build --no-cache -t 镜像名 .所以那些不经常改变的部分应该放在dockerfile内容的前面,那些频繁改动的部分应该放在后面。
移除没有使用中的镜像
docker image prune移除停止状态的容器
docker container pruneroot@ser745692301841:/dev_dir/dockerlab/avant# docker image
Usage: docker image COMMAND
Manage images
Commands:
build Build an image from a Dockerfile
history Show the history of an image
import Import the contents from a tarball to create a filesystem image
inspect Display detailed information on one or more images
load Load an image from a tar archive or STDIN
ls List images
prune Remove unused images
pull Download an image from a registry
push Upload an image to a registry
rm Remove one or more images
save Save one or more images to a tar archive (streamed to STDOUT by default)
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
Run 'docker image COMMAND --help' for more information on a command.可以看见有 rm Remove one or more images
docker image rm 镜像名字
docker image rm IMAGEIDdocker build -t docker-avant:0.0.1 ./root@ser745692301841:/dev_dir/dockerlab/avant# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-avant latest ae7b5f04f085 45 minutes ago 650MB
node alpine 0d3f5d817db1 8 days ago 168MB
ubuntu 25.04 482b635a13cd 8 days ago 77MB
redis latest f2cd22713a18 2 months ago 128MB
mongo latest ccf68b64aa3e 3 months ago 901MB
postgres latest 445ed93b882f 3 months ago 438MB
rabbitmq management 928da815d9a3 5 months ago 275MB
mysql latest 4c2531d6bf10 5 months ago 859MB
root@ser745692301841:/dev_dir/dockerlab/avant# docker build -t docker-avant:0.0.1 ./
DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
Install the buildx component to build images with BuildKit:
https://docs.docker.com/go/buildx/
Sending build context to Docker daemon 3.417MB
Step 1/10 : FROM ubuntu:25.04
---> 482b635a13cd
Step 2/10 : RUN apt update
---> Using cache
---> 2e2b66762d70
Step 3/10 : RUN apt install cmake g++ make git -y
---> Using cache
---> f4f7a3fa69d7
Step 4/10 : RUN apt install protobuf-compiler libprotobuf-dev -y
---> Using cache
---> c8365f8a1bb3
Step 5/10 : RUN apt install libssl-dev -y
---> Using cache
---> 89e1cc658d0d
Step 6/10 : WORKDIR /avant
---> Using cache
---> 1c44fb52b068
Step 7/10 : COPY ./ ./
---> Using cache
---> 59094d39a6c5
Step 8/10 : RUN rm -rf CMakeCache.txt && cd protocol && make && cd .. && mkdir build && rm -rf ./build/* && cd build && cmake .. && make -j3 && cd .. && cd bin && ls
---> Using cache
---> 5545133ce33e
Step 9/10 : WORKDIR /avant/bin
---> Using cache
---> d4c5825849a5
Step 10/10 : EXPOSE 20023 20024
---> Using cache
---> ae7b5f04f085
Successfully built ae7b5f04f085
Successfully tagged docker-avant:0.0.1
root@ser745692301841:/dev_dir/dockerlab/avant# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-avant 0.0.1 ae7b5f04f085 46 minutes ago 650MB
docker-avant latest ae7b5f04f085 46 minutes ago 650MB
node alpine 0d3f5d817db1 8 days ago 168MB
ubuntu 25.04 482b635a13cd 8 days ago 77MB
redis latest f2cd22713a18 2 months ago 128MB
mongo latest ccf68b64aa3e 3 months ago 901MB
postgres latest 445ed93b882f 3 months ago 438MB
rabbitmq management 928da815d9a3 5 months ago 275MB
mysql latest 4c2531d6bf10 5 months ago 859MB打出了两个 docker-avant 镜像但是 TAG不同,一个是 docker-avant:0.0.1 一个是 docker-avant:latest, 但是两者的 IMAGE ID是相同。
删除指定TAG的镜像:
root@ser745692301841:/dev_dir/dockerlab/avant# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-avant 0.0.1 ae7b5f04f085 48 minutes ago 650MB
docker-avant latest ae7b5f04f085 48 minutes ago 650MB
node alpine 0d3f5d817db1 8 days ago 168MB
ubuntu 25.04 482b635a13cd 8 days ago 77MB
redis latest f2cd22713a18 2 months ago 128MB
mongo latest ccf68b64aa3e 3 months ago 901MB
postgres latest 445ed93b882f 3 months ago 438MB
rabbitmq management 928da815d9a3 5 months ago 275MB
mysql latest 4c2531d6bf10 5 months ago 859MB
root@ser745692301841:/dev_dir/dockerlab/avant# docker image remove docker-avant:0.0.1
Untagged: docker-avant:0.0.1在build后再打TAG
root@ser745692301841:/dev_dir/dockerlab/avant# docker image tag docker-avant:latest docker-avant:1
root@ser745692301841:/dev_dir/dockerlab/avant# docker image tag ae7b5f04f085 docker-avant:2
root@ser745692301841:/dev_dir/dockerlab/avant# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-avant 1 ae7b5f04f085 50 minutes ago 650MB
docker-avant 2 ae7b5f04f085 50 minutes ago 650MB
docker-avant latest ae7b5f04f085 50 minutes ago 650MB
node alpine 0d3f5d817db1 8 days ago 168MB
ubuntu 25.04 482b635a13cd 8 days ago 77MB
redis latest f2cd22713a18 2 months ago 128MB
mongo latest ccf68b64aa3e 3 months ago 901MB
postgres latest 445ed93b882f 3 months ago 438MB
rabbitmq management 928da815d9a3 5 months ago 275MB
mysql latest 4c2531d6bf10 5 months ago 859MBhttps://hub.docker.com/
注册自己的账号。
先创建一个 repository https://hub.docker.com/repository/create , 免费计划中 一个账号只能由一个私有 repositories, 多了要付费才行。
docker tag local-image:tagname new-repo:tagname
docker push new-repo:tagname登录 docker后才能 push
root@ser745692301841:/dev_dir/dockerlab/avant# docker login -u gaowanlu
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credential-stores
Login Succeeded假设你在这台机器上有一个镜像,你想把它放在另一台机器上,但不经过docker hub。
在这种情况下,您可以将该映像保存为压缩文件并在另一台机器上加载。
root@ser745692301841:/dev_dir/dockerlab/avant# docker image save --help
Usage: docker image save [OPTIONS] IMAGE [IMAGE...]
Save one or more images to a tar archive (streamed to STDOUT by default)
Aliases:
docker image save, docker save
Options:
-o, --output string Write to a file, instead of STDOUTsave docker-avant镜像。
root@ser745692301841:/dev_dir/dockerlab/avant# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
docker-avant latest ae7b5f04f085 About an hour ago 650MB
node alpine 0d3f5d817db1 8 days ago 168MB
ubuntu 25.04 482b635a13cd 8 days ago 77MB
redis latest f2cd22713a18 2 months ago 128MB
mongo latest ccf68b64aa3e 3 months ago 901MB
postgres latest 445ed93b882f 3 months ago 438MB
rabbitmq management 928da815d9a3 5 months ago 275MB
mysql latest 4c2531d6bf10 5 months ago 859MB
root@ser745692301841:/dev_dir/dockerlab/avant# docker image save -o docker-avant.tar ae7b5f04f085
root@ser745692301841:/dev_dir/dockerlab/avant# ls
CMakeLists.txt Dockerfile LICENSE README.md bin build centos8.md client docker-avant.tar external protobuf.md protocol src test
root@ser745692301841:/dev_dir/dockerlab/avant# ll -lrth docker-avant.tar
-rw------- 1 root root 631M Oct 4 04:11 docker-avant.tar使用 image load
root@ser745692301841:/dev_dir/dockerlab/avant# docker image load --help
Usage: docker image load [OPTIONS]
Load an image from a tar archive or STDIN
Aliases:
docker image load, docker load
Options:
-i, --input string Read from tar archive file, instead of STDIN
-q, --quiet Suppress the load outputroot@ser745692301841:/dev_dir/dockerlab/avant# docker image load -i docker-avant.tar查看正在运行的容器
root@ser745692301841:/dev_dir/note# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES为一个镜像启动一个新的容器实例
docker run 镜像:tag或者镜像ID守护进程运行
docker run -d 镜像为docker容器进程起名字
docker run -d --name blue-sky react-app对于 docker run -d 运行的进程,我们不知道终端输出了什么。这可以通过Log来查看
docker logs 容器IDroot@ser745692301841:/dev_dir/note# docker logs --help
Usage: docker logs [OPTIONS] CONTAINER
Fetch the logs of a container
Aliases:
docker container logs, docker logs
Options:
--details Show extra details provided to logs
-f, --follow Follow log output
--since string Show logs since timestamp (e.g. "2013-01-02T13:23:37Z") or relative (e.g. "42m" for 42 minutes)
-n, --tail string Number of lines to show from the end of the logs (default "all")
-t, --timestamps Show timestamps
--until string Show logs before a timestamp (e.g. "2013-01-02T13:23:37Z") or relative (e.g. "42m" for 42 minutes)例如,查看最新的5行,并查看日志内容的时间戳
docker logs -n 5 -t 容器ID可以看到 docker ps,可以看到进程的PORTS
root@ser745692301841:/dev_dir/note# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES将主机的端口和容器的端口进行映射:
docker run -d -p 主机的端口:容器的端口 --name 进程名 镜像名当你启动一个容器时,它会执行我们在Dockerfile文件中指定的默认命令。
如果你想在稍后运行的容器中执行一个命令呢,使用 docker exec
docker exec 容器Name或者容器ID 命令行使用终端
docker exec -it 容器Name或容器ID bash
# 或者
docker exec -it 容器Name或容器ID sh停止容器
docker stop 容器名或ID重启容器
docker start c1docker start与docker run,有什么不同,使用docker run我们启动一个新的容器,而使用docker start我们启动一个已停止的容器。
有两种方法可以移除容器
docker container rm 容器名字或ID删除一个容器,这个容器不能为运行中。要么先停止然后rm,要么直接强制删除。
docker container rm -f 容器名字或ID查看全部容器,docker ps列出的只是运行中的,常看全部容器要加-a
docker ps -a一次性清除所有停止的容器
docker container prune每个容器都有自己的文件系统,对其他容器是不可见的。
如果我们删除容器,容器的文件系统也会随之消失,我们将会丢失我们的数据。
基本上我们永远不应该将数据存储在容器的文件系统中。
卷Volume是容器外部的存储。
root@ser745692301841:/dev_dir/note# docker volume
Usage: docker volume COMMAND
Manage volumes
Commands:
create Create a volume
inspect Display detailed information on one or more volumes
ls List volumes
prune Remove unused local volumes
rm Remove one or more volumes
Run 'docker volume COMMAND --help' for more information on a command.查看卷
root@ser745692301841:/dev_dir/note# docker volume ls
DRIVER VOLUME NAME
local docker_mysql-data
root@ser745692301841:/dev_dir/note# docker volume inspect docker_mysql-data
[
{
"CreatedAt": "2025-08-22T01:16:19Z",
"Driver": "local",
"Labels": {
"com.docker.compose.project": "docker",
"com.docker.compose.version": "1.29.2",
"com.docker.compose.volume": "mysql-data"
},
"Mountpoint": "/var/lib/docker/volumes/docker_mysql-data/_data",
"Name": "docker_mysql-data",
"Options": null,
"Scope": "local"
}
]其中的 Driver为local说明,卷在本地主机上,在 /var/lib/docker/volumes/docker_mysql-data/_data。也可以在云中创建卷的驱动程序, 如果您使用云平台,需要自己研究找到该云平台中创建卷的驱动程序。
创建卷 app-data
docker volume create app-data容器如何使用卷
docker run -d -p 4000:3000 -v app-data:/app/data react-app
# 如果使用一个未创建的卷,docker会自动创建
docker run -d -p 4000:3000 -v app-data2:/app/data react-app
# 如果镜像中没有目录 /app/data docker会自动在容器中创建 但是使用root用户创建的
# 需要注意用户权限问题同一个卷可以被挂载到多个容器上,可以在多个容器之间共享一个卷。
有时候我们需要在主机和容器之间复制文件,例如,我们假设在我们的容器中有这个日志文件,我们想要把它带到主机上进行分析。
root@ser745692301841:/dev_dir/note# docker cp --help
Usage: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH
Copy files/folders between a container and the local filesystem
Use '-' as the source to read a tar archive from stdin
and extract it to a directory destination in a container.
Use '-' as the destination to stream a tar archive of a
container source to stdout.
Aliases:
docker container cp, docker cp
Options:
-a, --archive Archive mode (copy all uid/gid information)
-L, --follow-link Always follow symbol link in SRC_PATH
-q, --quiet Suppress progress output during copy. Progress output is automatically suppressed if no terminal is attached# 将容器ID下的/app/log.txt 复制到主机的当前目录下
docker cp 容器ID:/app/log.txt ./同样可以从主机复制到文件到容器中
docker cp 主机文件 容器ID:/app/例如你是一个前端工程师,如改了一下html,如何 Publishing Changes
对于生产机器,你应该始终构建一个新镜像,正确标记它,然后部署。
对于开发环境,你不想在每次代码中做一个微小的修改时重启build新镜像,你可能说复制文件怎么样,但那也是一件麻烦事。
现实是,我们可以在主机上的一个目录和容器内部的一个目录之间创建映射或绑定。
Host Container
/project ------------ >/appdocker run -d -p 5001:3000 -v /project:/app/data 镜像
root@ser745692301841:/dev_dir/note# docker run -d -p 5001:3000 -v $(pwd):/app/data 镜像
# 等价于
docker run -d -p 5001:3000 -v /dev_dir/note:/app/data 镜像例如我们平时项目中,一般有前端项目、后端服务、DB、消息队列、Redis等,这些通常都是好多镜像,很多容器同意构成了整个大系统。
https://docs.docker.com/compose/install/
更方便的教程是直接去问 ChatGPT。
root@ser745692301841:/dev_dir/note# docker-compose --version
docker-compose version 1.29.2, build unknown删除所有容器
docker container rm -f $(docker container ls -aq)删除所有镜像
docker image rm -f $(docker image ls -q)例如我们有一个 前后端项目
backend(后端项目里有Dockerfile)
frontend(前端项目里有Dockerfile)
docker-compose.yml而且你还要准备 mongodb,但是有了 docker compose 这将使得部署环境变得简单。
docker-compose的文件,它是用来组合多容器应用程序的。
root@ser745692301841:/dev_dir/dockerlab# ls
backend docker-compose.yml frontend
root@ser745692301841:/dev_dir/dockerlab# docker-compose up可以一次性把 backend、frontend、database环境准备好。
JSON不在阐述,大家基本都知道,如
{
"name" : "hello",
"price": 148,
"is_published": true,
"tags": ["software", "devops"],
"author": {
"first_name": "wanlu",
"last_name": "gao"
}
}将上面json转为yaml或yml表述
---
name: hello
price: 148
is_published: true
tags:
- software
- devops
author:
first_name: wanlu
last_name: gaohttps://docs.docker.com/reference/compose-file/version-and-name/
在此我们不可能学习到全部内容,还是要多了解官方文档内容,像端口、卷、环境变量 都可以在 docker-compose中配置
docker-compose.yml
name: myapp
version: "3.8"
services:
web:
depends_on:
- api
build: ./frontend
ports:
- 3000:3000
environment:
DB_URL: mongodb://db/vidly
api:
depends_on:
- db
build: ./backend
ports:
- 3001:3001
db:
image: mongo:4.0-xenial
ports:
- 27017:27017
volumes:
- vidly:/data/db
volumes:
vidly: https://docs.docker.com/reference/compose-file/services/#depends_on
With the depends_on attribute, you can control the order of service startup and shutdown. It is useful if services are closely coupled, and the startup sequence impacts the application’s functionality.
root@ser745692301841:/dev_dir/dockerlab# docker-compose
Define and run multi-container applications with Docker.
Usage:
docker-compose [-f <arg>...] [--profile <name>...] [options] [--] [COMMAND] [ARGS...]
docker-compose -h|--help
Options:
-f, --file FILE Specify an alternate compose file
(default: docker-compose.yml)
-p, --project-name NAME Specify an alternate project name
(default: directory name)
--profile NAME Specify a profile to enable
-c, --context NAME Specify a context name
--verbose Show more output
--log-level LEVEL Set log level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
--ansi (never|always|auto) Control when to print ANSI control characters
--no-ansi Do not print ANSI control characters (DEPRECATED)
-v, --version Print version and exit
-H, --host HOST Daemon socket to connect to
--tls Use TLS; implied by --tlsverify
--tlscacert CA_PATH Trust certs signed only by this CA
--tlscert CLIENT_CERT_PATH Path to TLS certificate file
--tlskey TLS_KEY_PATH Path to TLS key file
--tlsverify Use TLS and verify the remote
--skip-hostname-check Don't check the daemon's hostname against the
name specified in the client certificate
--project-directory PATH Specify an alternate working directory
(default: the path of the Compose file)
--compatibility If set, Compose will attempt to convert keys
in v3 files to their non-Swarm equivalent (DEPRECATED)
--env-file PATH Specify an alternate environment file
Commands:
build Build or rebuild services
config Validate and view the Compose file
create Create services
down Stop and remove resources
events Receive real time events from containers
exec Execute a command in a running container
help Get help on a command
images List images
kill Kill containers
logs View output from containers
pause Pause services
port Print the public port for a port binding
ps List containers
pull Pull service images
push Push service images
restart Restart services
rm Remove stopped containers
run Run a one-off command
scale Set number of containers for a service
start Start services
stop Stop services
top Display the running processes
unpause Unpause services
up Create and start containers
version Show version information and quit上面的命令都将应用于我们的整个docker-compose应用程序,因此,这些命令中的大多数将映像我们应用程序中的多个服务或多个容器。
root@ser745692301841:/dev_dir/dockerlab# docker build --help
DEPRECATED: The legacy builder is deprecated and will be removed in a future release.
Install the buildx component to build images with BuildKit:
https://docs.docker.com/go/buildx/
Usage: docker build [OPTIONS] PATH | URL | -
Build an image from a Dockerfile
Aliases:
docker image build, docker build, docker builder build
Options:
--add-host list Add a custom host-to-IP mapping ("host:ip")
--build-arg list Set build-time variables
--cache-from strings Images to consider as cache sources
--cgroup-parent string Set the parent cgroup for the "RUN" instructions during build
--compress Compress the build context using gzip
--cpu-period int Limit the CPU CFS (Completely Fair Scheduler) period
--cpu-quota int Limit the CPU CFS (Completely Fair Scheduler) quota
-c, --cpu-shares int CPU shares (relative weight)
--cpuset-cpus string CPUs in which to allow execution (0-3, 0,1)
--cpuset-mems string MEMs in which to allow execution (0-3, 0,1)
--disable-content-trust Skip image verification (default true)
-f, --file string Name of the Dockerfile (Default is "PATH/Dockerfile")
--force-rm Always remove intermediate containers
--iidfile string Write the image ID to the file
--isolation string Container isolation technology
--label list Set metadata for an image
-m, --memory bytes Memory limit
--memory-swap bytes Swap limit equal to memory plus swap: -1 to enable unlimited swap
--network string Set the networking mode for the RUN instructions during build (default "default")
--no-cache Do not use cache when building the image
--platform string Set platform if server is multi-platform capable
--pull Always attempt to pull a newer version of the image
-q, --quiet Suppress the build output and print image ID on success
--rm Remove intermediate containers after a successful build (default true)
--security-opt strings Security options
--shm-size bytes Size of "/dev/shm"
-t, --tag list Name and optionally a tag in the "name:tag" format
--target string Set the target build stage to build.
--ulimit ulimit Ulimit options (default [])在 docker-compose.yml 文件的目录下执行, 将会build整个docker-compose 应用
docker-compose build
# 完全不用缓存rebuild
docker-compose build --no-cachedocker images 可以得到5个镜像,其中 vidly_frontend和vidly_backend 是build过程中产生的原始镜像, vidly_web、vidly_api 其实是从原始镜像打了TAG,它们的IMAGE_ID可以看出。
vidly_frontend
vidly_web
vidly_api
vidly_backend
mongoroot@ser745692301841:/dev_dir/myapp# docker-compose up如果compose镜像都准备好了,那么compose将在容器内运行它们,否则将自动构建镜像。
root@ser745692301841:/dev_dir/myapp# docker-compose up --help
Builds, (re)creates, starts, and attaches to containers for a service.
Unless they are already running, this command also starts any linked services.
The `docker-compose up` command aggregates the output of each container. When
the command exits, all containers are stopped. Running `docker-compose up -d`
starts the containers in the background and leaves them running.
If there are existing containers for a service, and the service's configuration
or image was changed after the container's creation, `docker-compose up` picks
up the changes by stopping and recreating the containers (preserving mounted
volumes). To prevent Compose from picking up changes, use the `--no-recreate`
flag.
If you want to force Compose to stop and recreate all containers, use the
`--force-recreate` flag.
Usage: up [options] [--scale SERVICE=NUM...] [--] [SERVICE...]
Options:
-d, --detach Detached mode: Run containers in the background,
print new container names. Incompatible with
--abort-on-container-exit.
--no-color Produce monochrome output.
--quiet-pull Pull without printing progress information
--no-deps Don't start linked services.
--force-recreate Recreate containers even if their configuration
and image haven't changed.
--always-recreate-deps Recreate dependent containers.
Incompatible with --no-recreate.
--no-recreate If containers already exist, don't recreate
them. Incompatible with --force-recreate and -V.
--no-build Don't build an image, even if it's missing.
--no-start Don't start the services after creating them.
--build Build images before starting containers.
--abort-on-container-exit Stops all containers if any container was
stopped. Incompatible with -d.
--attach-dependencies Attach to dependent containers.
-t, --timeout TIMEOUT Use this timeout in seconds for container
shutdown when attached or when containers are
already running. (default: 10)
-V, --renew-anon-volumes Recreate anonymous volumes instead of retrieving
data from the previous containers.
--remove-orphans Remove containers for services not defined
in the Compose file.
--exit-code-from SERVICE Return the exit code of the selected service
container. Implies --abort-on-container-exit.
--scale SERVICE=NUM Scale SERVICE to NUM instances. Overrides the
`scale` setting in the Compose file if present.
--no-log-prefix Don't print prefix in logs.查看 docker-compose 进程
root@ser745692301841:/dev_dir/myapp# docker-compose ps
Name Command State ...
vidly_api_1 ..... up ...
vidly_db_1 ..... up ...
vidly_web_1 ..... up ...关闭整个compose应用
root@ser745692301841:/dev_dir/myapp# docker-compose downDockerCompose 将自动创建一个网络,并将我们的容器添加到该网络中,这样不同容器就可以相互通信了
root@ser745692301841:/dev_dir/myapp# docker-compose up -d
Creating network "vidly_default" with the default driver
...docker network
root@ser745692301841:/dev_dir/dockerlab# docker network ls
NETWORK ID NAME DRIVER SCOPE
54d8cd91a4b0 bridge bridge local
8852c867c445 host host local
c33ae1c821b7 none null local
9fc9a8b8f73c vidly_default bridge localvidly_default 这个网络包含三个主机或三个容器 web、api、db
所以这些主机或这些容器可以使用它们的名称相互通信 例如 api的 DB_URL 写的是 mongodb://db/vidly
mongodb://IP地址/数据库名你可以进到 db 容器中
docker exec -it -u root db容器 sh
# 在db容器内执行 ping api
ping api
# 是可以ping通的背后原因是,docker附带一个嵌入式DNS服务器 DNS SERVER,其中包含这些容器的名称和IP
每个容器内部,有一个称为DNS解析器 DNS RESOLVER 的组件,这个DNS解析器与DNS服务器通信,以找到目标容器的IP地址。
当我们ping API容器时,这个DNS服务器会询问服务器API机器或API容器的IP是什么
docker-compose logs可以在一个地方查看这个应用程序所有容器的日志
root@ser745692301841:/dev_dir/dockerlab# docker-compose logs --help
View output from containers.
Usage: logs [options] [--] [SERVICE...]
Options:
--no-color Produce monochrome output.
-f, --follow Follow log output.
-t, --timestamps Show timestamps.
--tail="all" Number of lines to show from the end of the logs
for each container.
--no-log-prefix Don't print prefix in logs.当然可以仍用 docker logs 容器,来看指定容器的。
像原来单个容器一样使用卷
name: myapp
version: "3.8"
services:
web:
depends_on:
- api
build: ./frontend
ports:
- 3000:3000
environment:
DB_URL: mongodb://db/vidly
api:
depends_on:
- db
build: ./backend
ports:
- 3001:3001
volumes:
- ./backend:/app
db:
image: mongo:4.0-xenial
ports:
- 27017:27017
volumes:
- vidly:/data/db
volumes:
vidly: 其中的 api 映射了本地目录到容器,./backend 表示我们使用 docker-compose up 的所在目录下的backend目录
volumes:
- ./backend:/app大多数时候,当我们发布我们的应用程序时,我们希望我们的数据库具有特定的结构和一些数据,这被成为数据库迁移。
mongodb有个工具是 migratemongo,nodejs可以使用 migrate-mongo 依赖。
docker-compose.yml 覆盖 api 容器Dockerfile的CMD, migrate-mongo up 会执行项目里预备的db改动脚本(用js写的)
services:
api:
...
command: ./wait-for db:27017 && migrate-mongo up && npm start但是有个问题,在我们的api容器执行 migrate-mongo up 时,我们的db服务器根本尚未准备好 即使我们的db容器可能正在运行,因为启动数据库引擎通常需要几秒钟。
wait-for 就是为了等待db启动,才继续 && migrate-mongo up && npm start 剩余命令,wait-for https://github.com/vishnubob/wait-for-it
https://docs.docker.com/compose/how-tos/startup-order/
官方有一个样例,尽量用官方的相关特性
services:
web:
build: .
depends_on:
db:
condition: service_healthy
restart: true
redis:
condition: service_started
redis:
image: redis
db:
image: postgres
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"]
interval: 10s
retries: 5
start_period: 30s
timeout: 10s我们更该做的是,将DB的管理与docker管理进行分离,不要扯到一起,自动升级迁移数据库本身就是非常危险的事情。
当我们执行过 docker-compose down后,网络将会删除,但是卷不会
docker volume ls
DRIVER VOLUME NAME
local myapp_vidly
......myapp_vidly 前面 myapp 是 项目名称 后面vidly是卷名称。
前端开发在docker容器中进行npm test进行单元测试
name: myapp
version: "3.8"
services:
web:
depends_on:
- api
build: ./frontend
image: myapp_web:0.0.1
ports:
- 3000:3000
environment:
DB_URL: mongodb://db/vidly
web-tests:
image: myapp_web
volumes:
- ./frontend:/app
commands: npm test
api:
depends_on:
- db
build: ./backend
image: myapp_api:0.0.1
ports:
- 3001:3001
volumes:
- ./backend:/app
db:
image: mongo:4.0-xenial
ports:
- 27017:27017
volumes:
- vidly:/data/db
volumes:
vidly: 改了代码,直接进到 myapp_tests 容器终端中,去测试就好了
image: myapp_web:0.0.1 与 image: myapp_api:0.0.1 制定了 compose build出的镜像的TAG
将应用上 Cloud中。
Cluster Solutions有自己的编排工具,Docker Swarm 它并不是特别受欢迎。如今大多数人使用另一种工具, 成为 Kubernetes,它是一个Google的产品。
Kubernetes非常复杂,下面的我们将学习单主机的,一但你开始设计到集群你就去学Kubernetes。
Dev PROD
Docker Machine ----Docker Images----->安装Docker Machine 我们就可以在终端中执行docker命令,我们的命令将被发送到服务器上的docker引擎。
https://github.com/docker-archive-public/docker.machine
On Linux
$ curl -L https://github.com/docker/machine/releases/download/v0.16.2/docker-machine-`uname -s`-`uname -m` >/tmp/docker-machine &&
chmod +x /tmp/docker-machine &&
sudo cp /tmp/docker-machine /usr/local/bin/docker-machine后,执行
$ docker-machine --version
docker-machine version 0.16.2, build ....关于 docker-machine 在 2025/10/5 看的时候已经停止维护了,所以我们在此 Give Up It。
所以 去实践、去Kubernetes继续进步。
在前端中的生产环境的Dockerfile通常将 打包和部署分开如
Dockerfile.prod
# Step1
FROM node:14.16.0-alpine3.13 AS build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# Step2
FROM nginx:1.12-alpine
COPY --from=build-stage /app/build /usr/share/nginx/html
EXPOSE 80
ENTRYPOINT ["nginx", "-g", "daemon off;"]docker build -t myapp_web_opt -f Dockerfile.prod ./在docker-compose.prod.yml 更新
services:
web:
build:
context: ./frontend
dockerfile: Dockerfile.prod
ports:
- 80:80
restart: unless-stopped
...docker-compose -f docker-compose.prod.yml build在多个Docker Compose应用之间实现容器网络通信,可以通过Docker网络来完成。
理解 Docker 网络
Docker Compose 默认会为每个 Compose
文件创建一个独立的网络(通常命名为
<项目名>_default),因此不同 Compose
应用的容器默认是隔离的,无法直接通信。要让它们通信,需要让这些容器加入同一个
Docker 网络。
创建共享的 Docker 网络
为了让不同 Compose 应用的容器能够通信,可以创建一个共享的外部 Docker 网络,然后在每个 Compose 文件中引用这个网络。
创建外部网络:
docker network create shared-network修改Docker Compose文件:
在每个Docker Compose文件种,配置服务使用这个共享网络,假设你有两个Compose应用 app1 和 app2
app1/docker-compose.yml
version: '3.8'
services:
app1-service:
image: nginx
networks:
- shared-network
container_name: app1-container
networks:
shared-network:
external: trueapp2/docker-compose.yml
version: '3.8'
services:
app2-service:
image: redis
networks:
- shared-network
container_name: app2-container
networks:
shared-network:
external: true启动Compose应用
docker-compose -f app1/docker-compose.yml up -d
docker-compose -f app2/docker-compose.yml up -d容器间通信
在同一个Docker网络中,容器可以通过容器名称或服务名称直接通信(Docker提供内置的DNS解析)
示例:
假设 app1-container(Nginx服务) 想访问 app2-container(Redis服务)
curl http://app2-container:6379或者使用 Redis 客户端连接:
redis-cli -h app2-container -p 6379注意:
services:
app1-service:
networks:
shared-network:
aliases:
- app1-alias这样其他容器可以通过 app1-alias 访问 app1-service。
验证网络连通性
检查网络
docker network inspect shared-network确认 app1-container 和 app2-container 都在 shared-network 中。
测试连通性:
进入 app1-container:
docker exec -it app1-container bash然后 ping 或访问 app2-container:
ping app2-container注意事项
ports(如
ports: - "8080:80")。但容器间通信通过网络直接使用容器内部端口,无需映射到宿主机。docker network rm shared-network确保没有容器在使用该网络。
动态管理网络
如果多个 Compose 应用动态创建,可以编写脚本自动化创建和分配网络,或者在 Compose 文件中通过 network_mode: bridge 使用默认桥接网络(但不推荐,因为默认桥接网络的 DNS 解析不如自定义网络方便)。
不同主机上的Docker Compose应用之间可以通过配置适当的Docker网络实现通信,但由于容器运行在不同的物理或虚拟主机上,无法直接使用默认的bridge网络(如单主机场景)。需要使用支持跨主机通信的网络模式,例如 overlay 网络(通常与Docker Swarm或其他容器编排工具配合使用)。
1. 使用Docker Swarm的Overlay网络
基本没人用,大家都在用 kubernetes。
初始化Docker Swarm: 在其中一台主机(主节点)上初始化Swarm
docker swarm init这回生成一个加入Swarm的令牌 token,在其他主机(工作节点)上运行一下命令加入Swarm:
docker swarm join --token <token> <主节点IP>:<端口>例如:
docker swarm join --token SWMTKN-1-xxx 192.168.1.100:2377创建Overlay网络:在主节点上创建一个overlay网络:
docker network create --driver overlay --attachable shared-overlay-network--driver overlay:指定使用 overlay 网络。--attachable:允许独立容器(如 Docker Compose
创建的容器)加入该网络。shared-overlay-network:自定义网络名称。修改 Docker Compose 文件:在每个主机的 Docker Compose 文件中,配置服务使用这个 overlay 网络。例如:
主机1的docker-compose.yml
version: '3.8'
services:
app1-service:
image: nginx
container_name: app1-container
networks:
- shared-overlay-network
networks:
shared-overlay-network:
external: truea主机2的docker-compose.yml
version: '3.8'
services:
app2-service:
image: redis
container_name: app2-container
networks:
- shared-overlay-network
networks:
shared-overlay-network:
external: true部署Compose应用:在每台主机上运行 Docker Compose:
docker-compose up -d验证通信:
docker exec -it app1-container bash
ping app2-container或访问 Redis 服务:
redis-cli -h app2-container -p 6379注意事项
2. 使用外部编排工具 Kubernetes
如果不适用Docker Swarm,可以考虑Kubernetes,它通过自己的网络模型(CNI 插件,如Flannel或Calico)支持跨主机容器通信。
Kubernetes的学习曲线陡峭,适合复杂或大规模应用,需要额外的Kubernetes集群管理。
3. 直接通过主机IP和端口映射
如果不使用编排工具,可以通过主机间的 IP 和端口映射实现通信,但这不是推荐方式,因为缺乏动态性和 DNS 解析。
在Docker Compose文件中映射容器端口到主机;
version: '3.8'
services:
app2-service:
image: redis
ports:
- "6379:6379"从另一主机的容器通过主机IP和映射端口访问:
redis-cli -h <主机2的IP> -p 6379缺点:
运行以下命令查看当前使用的 Context 和所有可用 Context:
docker context ls输出示例:
NAME DESCRIPTION DOCKER ENDPOINT
default * Current DOCKER_HOST based configuration unix:///var/run/docker.sock
remote Remote server tcp://192.168.1.100:2376创建一个指向远程 Docker 主机的 Context,例如:
docker context create remote --docker "host=tcp://192.168.1.100:2376,ca=/path/to/ca.pem,cert=/path/to/cert.pem,key=/path/to/key.pem"切换到另一个 Context:
docker context use remote切换后,Docker CLI 的所有命令(如 docker ps、docker run)都会针对 remote 主机执行。这边与自动化脚本管理不同主机上的容器,只要切换context 然后执行docker命令。
检查某个Context的配置
docker context inspect remote删除不再需要的 Context:
docker context rm remote即使未切换 Context,也可以在命令中指定 Context:
docker --context remote ps这会在 remote 主机上运行 docker ps,而不改变当前默认 Context。
Docker Contexts 支持多种类型的端点(endpoint):
unix:///var/run/docker.sock(Linux/Mac)或
npipe:////./pipe/docker_engine(Windows)。tcp://<主机>:<端口>,支持 TLS
或非加密连接。ssh://user@host,使用 SSH 隧道连接远程
Docker。Docker Compose 支持 Context,可以指定某个 Context 来运行 Compose 命令。例如:
docker-compose --context remote up -d这会将 Compose 应用的部署目标设置为 remote 主机的 Docker 守护进程。
为每台主机创建一个 Context:
docker context create host1 --docker "host=tcp://192.168.1.100:2376"
docker context create host2 --docker "host=tcp://192.168.1.101:2376"部署Compose应用到不同主机
docker-compose --context host1 -f app1/docker-compose.yml up -d
docker-compose --context host2 -f app2/docker-compose.yml up -d使用 overlay 网络(如前文所述)实现跨主机通信。
Docker Contexts 是一个强大的工具,用于管理多个 Docker 环境(本地、远程、Swarm、Kubernetes),通过简单的命令切换控制目标。它特别适合需要操作多个 Docker 主机的场景,与 Docker Compose 结合可以简化跨主机部署和通信。