基础
Docker是个啥?
Docker,衍生于LXC,Linux Container。LXC提供了轻量级的虚拟化,因为人们发现虚拟机隔离环境的代价太大了,而轻量级的虚拟化可以做到「隔离进程和资源」。
Docker是在LXC的基础上,基于Golang开发,再提供了一系列强大功能。
所以,可以简单理解,Docker是功能强大的开源的容器化工具,一种轻量级的虚拟化工具。
其目的是,解决开发环境和生产环境不一致的问题,缩短开发到测试部署到上线的周期。
用Docker可以做什么?
作为开发者,可以将开发好的应用与依赖包,打包到一个环境中,方便地在任意服务器上运行。
这个打包的环境,就是「容器」,轻量级开销小、可移植。
很大程度省去在「依赖、环境搭建」上耗费的时间,安装软件的时候,直接将环境也复制过来,直接就可以跑起来了。
(1)提供一次性的环境。比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。
(2)提供弹性的云服务。因为 Docker 容器可以随开随关,很适合动态扩容和缩容。
(3)组建微服务架构。通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。
容器 vs 虚拟机
容器轻量,共用一个操作系统,每个容器是个独立的进程。
虚拟机较重,各自运行了个操作系统。
镜像 & 容器 & 仓库
镜像image
:
是个二进制文件,包含了运行应用时所有需要的东西:代码、依赖库、环境变量、各种配置文件。
- 镜像images是死的模板,容器container是活的进程。通过镜像启动容器。
- 一般,优先基于已经提供的镜像定制,生成自己需要的镜像!而不是从头制作。
- 镜像本质就是叠加的文件系统:
容器container
:
就是镜像运行起来的实例进程。
进入到容器中,会发现就像是一个简易版的Linux环境和运行在其中的应用。
一般要指定几样东西,才能运行起来容器:
- 镜像
- 计算资源的配置
- 网络配置和安全策略
- 运行的命令
仓库Registry
:
集中存放各种镜像的地方。
仓库也分为公/私两种,最大的公开仓库是Docker Hub
。用户可以再Docker hub
上保存私有镜像,也可以架设自己的私有Registry
。
架构
Docker是个C/S架构的工具。
平常命令都是在操作Docker Client
,把命令发给Docker Server
去真正处理,返回结果。
而这里的Client也可以连接远程的宿主机上的server。
架构中的几大模块:
Docker Client
:用户使用的客户端,用来和Docker Daemon
通信。Docker Daemon
:以root启动的后台守护进程,会启动Docker Server
,接受处理 docker client的请求,细分:- docker server
- engine
- job
Docker Registry
:镜像仓库的托管服务。最大的就是Docker Hub
Graph
:管理本地的镜像Driver
:驱动模块。为了解耦逻辑。libcontainer
: Go语言编写的库,便于Docker的底层操作,用于直接访问内核中与容器相关的API。Docker Container
: 容器,Docker服务最终提供的东西。
命令
docker --version
当前docker版本docker info
当前docker的配置信息
镜像
1 列出本地已下载镜像
docker images [xxx]
可以查看指定的镜像,默认查看所有镜像。
~ ❯ docker images python 47s 09:28:24
REPOSITORY TAG IMAGE ID CREATED SIZE
python latest a5d7930b60cc 5 months ago 917MB
~ ❯ docker images 09:28:56
REPOSITORY TAG IMAGE ID CREATED SIZE
python latest a5d7930b60cc 5 months ago 917MB
grafana/grafana latest e511606aee56 11 months ago 206MB
prom/prometheus latest 9dfc442be98c 11 months ago 189MB
docker/getting-started latest 083d7564d904 12 months ago 28MB
nacos/nacos-server 2.0.1 90c4c6c5d925 13 months ago 1.04GB
nacos/nacos-mysql 5.7 72037eccf264 2 years ago 373MB
2 搜索
docker search xxx
查找并列出可用的版本。
- 注意看
STARS
和OFFICIAL
这两个指标再参考是否使用该镜像。
比如找Python镜像:
~ ❯ docker search python 09:14:09
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
python Python is an interpreted, interactive, objec… 7548 [OK]
pypy PyPy is a fast, compliant alternative implem… 325 [OK]
circleci/python Python is an interpreted, interactive, objec… 49
hylang Hy is a Lisp dialect that translates express… 45 [OK]
bitnami/python Bitnami Python Docker Image 19 [OK]
cimg/python 5
clearlinux/python Python programming interpreted language with… 5
okteto/python-fastapi 0
appdynamics/python-agent-init AppDynamics Repository for Python agent inst… 0
pachyderm/python-build 0
bitnami/python-snapshot 0
mirantis/python-operations-api https://mirantis.jira.com/browse/IT-40189 0 [OK]
okteto/python 0
pipelinecomponents/python-safety Safety by pyup.io for Python in a container … 0
itisfoundation/python-with-pandas 0
...
3 下载镜像
docker pull xxx
比如Python最新版本镜像:
~ ❯ docker pull python 09:18:21
Using default tag: latest
latest: Pulling from library/python
0e29546d541c: Pull complete
9b829c73b52b: Pull complete
cb5b7ae36172: Pull complete
6494e4811622: Pull complete
6f9f74896dfa: Pull complete
fcb6d5f7c986: Pull complete
290438add9da: Pull complete
ab11df61f44a: Pull complete
de4793a5fa46: Pull complete
Digest: sha256:dbbfcbf95f6b596d2be1d8f3b368016619f78f829facf6f2e361bea1151794e5
Status: Downloaded newer image for python:latest
docker.io/library/python:latest
4 删除镜像
docker rmi <IMAGE_ID或镜像名>
镜像有的很大,占磁盘空间,用不到的就可以删除。
- 删除前需确定没有容器正在使用这个镜像,才能删除成功!
- 删除时的每一行
Deleted
,代表了一个镜像层。
~ ❯ docker rmi -f a5d7930b60cc 09:29:05
Untagged: python:latest
Untagged: python@sha256:dbbfcbf95f6b596d2be1d8f3b368016619f78f829facf6f2e361bea1151794e5
Deleted: sha256:a5d7930b60cc41d81b2b1d47efb5d26f7fafb587c97e539002dce3f85e1b51d2
Deleted: sha256:c4be672401dfb89efbbc7061f11720f8592c2100b39b4ec1e3c4503fd9a837ad
Deleted: sha256:8fcdb709f4c7699590664a5a048c3179950183962030407d37ad309c085f53f4
Deleted: sha256:81b94b62a2459b342bb99906fe678d7ce8b0b4c36cfccda43fe5daf6426674d1
Deleted: sha256:06d8166db74268768077df3896e5b7359e5f38abcf80db257c809647cfef7a58
Deleted: sha256:29a8de6a9ba3858e830b20b810f426bef144944a5c998ce4c53762ab9165e2d6
Deleted: sha256:cbce712ed17923285239f9d9c0528984aef065b7413d68a0290e2c8eecc98f4a
Deleted: sha256:aa56d037ee5925ebf11127c3e1f617874c4ce8bae6b6af7d132b7f7a4a606e6f
Deleted: sha256:97e5f44efb543d466c5847602654a8cb22c9466b61d04988d47ec44b197ea874
Deleted: sha256:11936051f93baf5a4fb090a8fa0999309b8173556f7826598e235e8a82127bce
5 导出、导入
docker save nginx > /tmp/nginx.tar.gz
docker load < /tmp/nginx.tar.gz
6 构建
docker build
具体见下文 Dockerfile
。
7 推送到docker hub
docker push <镜像名>
容器
1 查看
docker ps
查看运行中的容器。
-a
显示所有容器,包括未运行的
~ ❯ docker ps 09:41:01
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
~ ❯ docker ps -a 09:59:40
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c1dc1d07e0b8 nacos/nacos-mysql:5.7 "docker-entrypoint.s…" 10 months ago Exited (0) 10 months ago mysql
1b24c1e771da 9dfc442be98c "/bin/prometheus --c…" 10 months ago Exited (0) 10 months ago prometheus
75fba70a17dd e511606aee56 "/run.sh" 10 months ago Exited (0) 10 months ago grafana
2 运行
docker run -it xxx_image_name /bin/bash
新建且运行一个容器,并自动进入容器。
-it
在开启的伪终端中与容器进行交互- 常组合用。-i表示开启容器的
STDIN
,能够支持输入,-t表示开启伪tty终端,让容器提供一个交互式shell。
- 常组合用。-i表示开启容器的
-d
后台运行容器- 上面命令没有-t,一旦退出容器则自动停止运行容器!
- 末尾的
/bin/bash
表示启动容器后第一个执行的命令- 在-it模式必须指定,否则不知道用什么shell环境进行交互
-p
本机和容器内的「ip、端口」映射- 避免使用容器每次随机返回的ip地址,以及以及映射到宿主机随机的端口上。
- 映射的容器端口,需要在镜像定义时先EXPOSE暴露出来
--name
为运行起来的容器设置一个名称,建议使用,便于管理--rm
停止时,自动删除容器文件-v
设置卷的映射,覆盖VOLUME
指令。用于数据管理、代码修改。
3 进入
docker exec -it xxx_container_name /bin/bash
像run命令,但不创建启动新容器,退出shell也不会导致容器停止。
- 一般是进入到用后台方式运行的容器中。
- 结合-d后台启动的方式,可以在另外的终端用exec进入容器,不会占用当前终端!
4 停止与启动
docker stop <容器ID或容器名>
docker start <容器ID或容器名>
只是 停止/启动 后台运行的容器。
容器一旦启动过,就会生成这个容器的「容器文件」,即便停止了也不会删除。
5 删除
docker rm <容器ID或容器名>
当确定不需要这个容器后,容器会占用磁盘空间,那么建议在停止容器后删除掉。
6 拷贝文件
docker cp 本机路径 容器id:文件路径
主机内容 -> 容器
docker cp 容器id:文件路径 本机路径
容器内容 -> 主机
7 查看运行时的输出信息
docker logs <容器ID或容器名>
容器若后台运行,就没有终端可以立即看到容器运行时在标准输出显示了什么。可以通过该命令查看。
-f
跟踪日志输出。就像 tail -f 一样。-t
为每条日子项加上时间戳,方便区分。
Dockerfile
用于构建镜像。通过**Dockerfile**
,定义想要生成什么样的自定义镜像。
虽然下载的镜像可以直接运行为容器了,但实际使用中常常要基于已有的镜像定制化修改,也就是创建自定义的镜像文件,再运行为容器。
这个过程就要用到Dockerfile
和docker build
命令。
可参考:Docker在微服务上的应用示例 以及 官方文档
Dockerfile中常用指令:
-
FROM
:基于的基础镜像 MAINTAINER
:该镜像的维护者信息RUN
:构建过程中需要运行的命令。可以多条指令,结果都会打包到镜像文件中。- 会在shell里使用
/bin/sh -c
来执行命令 - 如果平台不支持shell或者不希望在shell中运行(避免shell字符串篡改),可以用
exec
格式的RUN指令,即数组表示指定命令和参数。
- 会在shell里使用
COPY
:将本地文件拷贝到容器中- 目的地址,需要用容器内的绝对路径,若不存在,会自动创建路径。
ADD
:高级的copy
命令。比如自动解压文件等ENV
:构建过程中设置的环境变量,便于构建过程中使用。可以多个。WORKDIR
:设置当前工作目录VOLUME
:设置数据卷EXPOSE
: 暴露端口给宿主机。可以暴露多个端口。CMD
:区别于RUN
,这是在容器启动后才执行的命令。- 只能一条
CMD
,等价于docker run启动容器时的某尾那条命令!docker run会覆盖这里!
- 只能一条
ENTRYPOINT
:和CMD
类似,都是在启动容器后执行命令。- 文件中只能最后一句生效,相当于只能有一句。
- 但不会容易被docker run命令覆盖。(需要–entrypoint参数覆盖)
- 通常用法是,
ENTRYPOINT
用来执行固定脚本或命令,CMD
可以为ENTRYPOINT
额外传参,即docker run时命令末尾传入的参数。 - 例子:这样如果docker run 传参数,就覆盖CMD指令,用参数来启动nginx。如果不传,则用CMD默认的-h来显示帮助命令。
... ENTRYPOINT ["/usr/sbin/nginx"] CMD ["-h"]
构建的细节:
- Dockerfile 所在的目录,也称为构建环境/构建上下文,build时涉及的代码、文件、数据都会基于这个路径。
- Dockerfile 同级目录中,放置
.dockerignore
文件,来忽略成为构建上下文的文件,不提交给守护进程,避免镜像过大。 - 每条指令,都会创建一层新的镜像层并提交成为镜像。
- 如果构建时因为某条指令而失败了。仍会得到一个镜像,可以运行起来成为一个具备交互功能的容器,可以进入其中去调试失败的指令。
- 每一层镜像层,都可认为是一层缓存。
- 如果重新构建,并不需要从头构建!哪里最早修改了指令,那么就基于上一层缓存的镜像层,从这条指令开始重新构建后续所有的镜像层。这个默认缓存机制极大节省了时间!
- 卷的内容,不会构建到镜像中。
构建命令:
docker build -t xxx .
-t
指定镜像名及标签- 镜像的命名:
仓库名:版本号标签
或者用户名/仓库名:版本号标签
- 若未指定,自动为其设置一个
latest
标签。
- 镜像的命名:
- 末尾的
.
表示在当前路径下寻找Dockerfile,也可以填写远程Git仓库的Dockerfile位置来构建! - 加上
--no-cache
参数,表示不使用旧的缓存进行镜像构建。
自动构建:
在推送代码到远程仓库时,可以触发在Docker bub上自动构建对应的镜像。
多阶段构建:
Docker Compose
多容器编排管理工具。
当运行多个容器时,要手动去按某种顺序逐个启动,还要考虑容器之间传递的连接信息参数。容器一多,协调就很繁琐了!所以,诞生了容器管理工具。
比如,大名鼎鼎的Kubernetes
、Docker官方的Docker Compose
等等。
Docker Compose VS Kubernetes
都是用于管理和部署多容器应用程序的工具。
共同点:
- 都基于 docker 容器引擎,也就是说都要使用 docker 来创建和运行容器。
- 都使用 YAML 文件来定义应用程序的服务、网络和数据卷等组件
- 都可以实现容器的快速部署、自动恢复、负载均衡、服务发现等功能,提高应用程序的可用性和可扩展性。
优缺点:
- 安装和使用的难易度:
- docker compose 相对简单,只需要安装 docker 就可以使用。
- k8s 相对复杂,需要安装和配置多个组件,如 kubelet, kubeadm, kubectl 等,还需要考虑集群的网络、存储、安全等问题。
- 功能和扩展性:
- docker compose 的功能相对有限,是一个单主机的容器编排工具,不能跨主机部署和管理容器。主要适用于单机或少量机器的容器编排。
- 而 k8s 的功能相对丰富,是一个跨主机的集群部署工具。主要适用于跨主机或大规模的容器编排,形成一个分布式的容器平台。还提供了服务发现、服务网格、服务目录、服务监控等功能,以及丰富的插件和生态系统。
- 资源占用和性能:
- docker compose 相对轻量,占用的资源较少,性能较高。
- 而 k8s 相对重量,占用的资源较多,性能较低,因为它需要维护多个组件和状态。
- 适用场景:
- docker compose 主要适用于开发和测试环境,或者单机部署简单应用。
- 而 k8s 主要适用于生产环境,或者跨主机部署高可用应用。
总的来说,docker compose 和 k8s 都有各自的优势和劣势,没有绝对的好坏,需要根据具体的需求和场景来选择合适的工具。
docker-compose VS docker compose
两者都可以用来定义和运行多容器的Docker应用程序,但是有一些细微的差别。
docker-compose
是一个独立的可执行文件。用Python编写的项目,它使用了一个名为docker-compose.yml
的文件来配置服务。它是Docker Compose
的第一代版本,现在已经被废弃,开发转移到了第二代版本。
docker compose
是docker命令的一个子命令。用Go编写的项目,它使用了一个名为compose-spec
的规范来配置服务,其实也是默认使用docker-compose.yml
配置文件。它是Docker Compose
的第二代版本,被内置到了Docker CLI
中,作为一个插件。
推荐使用docker compose
命令来替代docker-compose
命令,语法和功能基本相同。
使用docker compose
的优势:
- 更快地启动和停止服务。
- 更好地处理依赖和并发。
- 更好地处理错误和日志。
- 更好地与其他docker子命令集成,比如docker build, docker push等。
- 支持更多的Compose文件特性,比如profiles, extends等。
- 支持更多的平台和后端,比如Kubernetes, Amazon ECS等。
docker-compose.yml
用于配置多容器的各个服务,具体的容器启动细节。
文件放在项目根目录下即可。
主要在services
下定义不同容器中的服务。比如:后端服务、前端服务、数据库服务、缓存服务等等。
services
各个服务的配置项:
build
指定Dockerfile所在的相对路径,编译后启动容器image
指定现成的镜像 来启动容器ports
与expose
有什么差别?- 都是暴露端口的方法
ports
是将内部端口,暴露给主机和其他容器expose
不会暴露给主机,仅暴露给其他容器。
depends_on
依赖服务- 默认只是确定容器之间启动的先后顺序。并不会等待容器中服务准备好才启动下一个容器!
- 比如“要等待数据库容器启动并准备好”,就要补充用到
condition: service_healthy
配置!被依赖的服务就要配置状态检查:healthcheck
volumes
数据卷- 可以用于数据库持久化数据。
- 也可以用于开发时挂载本地代码路径,便于修改实时生效,而不用重新编译镜像重启容器。
env_file
加载文件中配置的环境变量- 一般会用
.env
文件,里边定义好当前环境需要的环境变量,比如:数据库连接配置、Django项目key,各种敏感信息。
- 一般会用
networks
定义和管理容器的网络。- 默认会创建一个名为
<projectname>_default
的网络,其中 projectname 是 docker-compose.yml 所在目录的名称。所有的服务都会加入到这个默认网络中,并且可以通过服务名称互相访问。 - 如果不需要自定义网络,就不用指定 networks 的配置,使用默认网络即可。
- 常用网络连接方式:
- bridge:桥接模式,是默认的网络模式。在这种模式下,docker 守护进程会为每个容器分配一个网络接口,并连接到一个
docker0
虚拟网桥上。容器之间可以通过 IP 地址或服务名称互相访问,也可以通过端口映射让宿主机或外部网络访问容器。适用于大多数场景,尤其是需要多个容器互相通信的场景。 - host:主机模式,是一种特殊的网络模式。在这种模式下,容器不会获得一个独立的网络空间,而是直接使用宿主机的网络空间。容器可以直接访问宿主机的所有网络服务和端口,但是不能与其他容器通信,也不能使用服务名称或别名。这种模式适用于需要高性能或特殊网络需求的场景,例如需要使用原始套接字的场景。
- none:无网络模式,是一种极端的网络模式。
- service:服务模式,是一种复用其他服务网络的模式。
- container:容器模式,是一种复用其他容器网络的模式。
- bridge:桥接模式,是默认的网络模式。在这种模式下,docker 守护进程会为每个容器分配一个网络接口,并连接到一个
- 默认会创建一个名为
compose 命令
docker compose
会默认使用当前路径下docker-compose.yml
配置文件。所以要在该文件位置执行命令。
-f <other-docker-compose.yml>
以下所有命令,可以通过该参数使用其他配置文件。docker compose ps
查看容器进程docker compose up [services]
启动容器服务,默认是配置文件中的所有容器服务-d
使这一组容器服务后台运行,避免前台ctrl+C
意外退出--build
启动容器前,都重新编译镜像文件,让修改的Dockerfile生效。
docker compose exec <service> /bin/bash
进入容器交互式执行命令docker compose logs [services]
查看服务输出在标准输出的日志docker compose stop [services]
停止容器服务docker compose down
基于配置文件,停止并删除所有容器。docker compose build <service>
重新编译某个服务的镜像--no-cache
不使用缓存镜像层,完全重新编译
Docker 持续集成
Docker可以快速创建和处理多个容器。
这个特点天然地适合测试场景里:频繁安装软件、搭建环节、部署测试、再清理环境。
Docker使得这些部署和清理环境的开销变得很低。
Volumes
数据卷。
绕过Docker底层的「联合文件系统」,让容器中的数据持久化到宿主机上,且能被多个容器共享数据。
- 数据持久化:即便容器被销毁,新的容器运行起来后,仍然可以获取到原来已经生成的数据。
- 让容器内的目录在本机的某个位置也能访问到,方便实时修改。比如:在本地开发时,代码改动非常频繁,不想重复构建镜像!
- 设置的卷,不会被包含到镜像中!
- 卷,会默认放在宿主机的一个路径下。如果指定了本地目录映射到挂载点,那么数据卷内容就会放在这个指定路径下。
镜像到容器的简单实践
一个简单的Django项目,用Docker启动提供服务,期望的环境是「centos7 + python3.7」。
创建镜像的过程,遇到了镜像版本导致的环境问题。
# FROM centos
# 将软件包信息在本地建立索引缓存,提高搜索安装软件的速度。centos 7才有
# RUN yum makecache fast;
# 安装Python3基本环境
# RUN yum -y install python3-devel python3-pip
# 由于centos7下边手动装的python3太低了。很多依赖库安装会出错
# 所以使用了现成的集成好centos和python37的镜像
FROM recognai/python-37-centos
# 由于这个镜像中默认的python被改向了python3,导致yum使用出问题,因此做个调整
RUN rm -rf /usr/bin/python && ln -s /usr/bin/python2 /usr/bin/python
# 项目用到了MySQL,需要配置MySQL环境
RUN yum install -y mysql-devel
# 安装项目依赖环境
COPY requirements.txt /opt
RUN pip3 install -r /opt/requirements.txt
# WORKDIR /opt
# EXPOSE 8000
# CMD ["python3","main.py"]
编译镜像成功后的提示:
~ ❯ docker build -t my_django_web . --no-cache
[+] Building 29.6s (10/10) FINISHED
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 868B 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 34B 0.0s
=> [internal] load metadata for docker.io/recognai/python-37-centos:latest 0.0s
=> CACHED [1/5] FROM docker.io/recognai/python-37-centos 0.0s
=> [internal] load build context 0.0s
=> => transferring context: 38B 0.0s
=> [2/5] RUN rm -rf /usr/bin/python && ln -s /usr/bin/python2 /usr/bin/python 0.3s
=> [3/5] RUN yum install -y mysql-devel 14.2s
=> [4/5] COPY requirements.txt /opt 0.0s
=> [5/5] RUN pip3 install -r /opt/requirements.txt 14.0s
=> exporting to image 1.0s
=> => exporting layers 1.0s
=> => writing image sha256:a4b8785b454b6f249726c61d7ad1db4a94f21dc141b86c1f64f96b64b4788e8c 0.0s
=> => naming to docker.io/library/my_django_web 0.0s
Use 'docker scan' to run Snyk tests against images to find vulnerabilities and learn how to fix them
进入容器,检查下环境:
~ ❯ docker run -itd my_django_web /bin/bash
0cf3c1b52a4f45e4b848ae6a0adadf5c810f027ad4d7176d680d905838682f5e
~ ❯ docker exec -it 0cf3c1b52a4f45e4b848ae /bin/bash
[root@0cf3c1b52a4f /]#
[root@0cf3c1b52a4f /]# cat /etc/redhat-release
CentOS Linux release 7.7.1908 (Core)
[root@0cf3c1b52a4f /]# python --version
Python 2.7.5
[root@0cf3c1b52a4f /]# python3 --version
bash: python3: command not found
[root@0cf3c1b52a4f /]# python3.7 --version
Python 3.7.4
[root@0cf3c1b52a4f /]# pip
pip pip3 pip3.7 pipenv pipenv-resolver
[root@0cf3c1b52a4f /]# pip --version
pip 19.3.1 from /usr/local/lib/python3.7/site-packages/pip (python 3.7)
[root@0cf3c1b52a4f /]# pip list
Package Version
------------------- ----------
asgiref 3.5.2
attrs 21.4.0
black 22.3.0
certifi 2019.11.28
click 8.1.3
Django 3.2.13
django-cors-headers 3.12.0
djangorestframework 3.13.1
importlib-metadata 4.11.4
iniconfig 1.1.1
mypy-extensions 0.4.3
mysqlclient 2.1.0
packaging 21.3
pathspec 0.9.0
pip 19.3.1
pipenv 2018.11.26
platformdirs 2.5.2
pluggy 1.0.0
py 1.11.0
pyparsing 3.0.9
pytest 7.1.2
pytz 2022.1
setuptools 42.0.2
sqlparse 0.4.2
tomli 2.0.1
typed-ast 1.5.4
typing-extensions 4.2.0
virtualenv 16.7.8
virtualenv-clone 0.5.3
wheel 0.33.6
zipp 3.8.0
WARNING: You are using pip version 19.3.1; however, version 22.2.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
当然,实际上不会仅用一个容器就足够的。更成熟的是分成多个服务模块,分别用不同容器启动,互相之间进行通信。
这要用到容器管理工具了。
比如当前这个demo用到了MySQL,而如果这个镜像中没有手动安装启动MySQL,可以另外用一个现成的MySQL镜像启动一个容器,再用docker-compose
编排,启动多容器服务。