1.1-docker
Create by fall on 09 May 2023
Recently revised in 06 Nov 2025
Docker
目前,我们有三个不同的软件运行方式:
物理机、虚拟机、容器
- 物理机时代:多个应用会跑在一台机器上(更换环境,需要更换对应的机器)
- 虚拟机时代:一台物理机通过虚拟机运行多个环境,环境分别运行多个程序(VMware,在 mac 系统上我装一个 Windows 系统,装一个 CuteFish)
- 容器化时代:一台物理机安装多个容器实例,多个实例运行多个程序,比虚拟机更小(docker,一个容器,使用一个进程,作为一个模拟系统)
docker 提供了容器化部署的能力,docker 开发,一般是以下的几个过程。
- 在
Dockerfile目录内开发 - 开发完成后创建镜像(覆盖镜像)
- 最后创建容器,运行容器。
**Docker 属于 Linux 容器的一种封装,提供简单易用的容器使用接口。**它是目前最流行的 Linux 容器解决方案。
Docker 将应用程序与该程序的依赖,打包在一个文件里面。运行这个文件,就会生成一个虚拟容器。程序在这个虚拟容器里运行,就好像在真实的物理机上运行一样。有了 Docker,就不用担心环境问题。用户可以方便地创建和使用容器,把自己的应用放入容器。容器还可以进行版本管理、复制、分享、修改,就像管理普通的代码一样。
Docker 的主要用途,目前有三大类。
- 提供一次性的环境:比如,本地测试他人的软件、持续集成的时候提供单元测试和构建的环境。
- 提供弹性的云服务:因为 Docker 容器可以随开随关,很适合动态扩容和缩容。
- 组建微服务架构:通过多个容器,一台机器可以跑多个服务,因此在本机就可以模拟出微服务架构。
实际使用中,业务发展初期只有几个微服务,这时用 Docker 就足够了,但随着业务规模逐渐扩大,容器越来越多,运维人员的工作越来越复杂,这个时候就需要容器编排系统。
安装
参照官网安装步骤安装即可
附:国内可用 Docker 镜像源汇总
https://www.coderjia.cn/archives/dba3f94c-a021-468a-8ac6-e840f85867ea
主要概念
镜像
镜像(Image):一个系统的一瞬间进行保存,可以不断地从该点创建分支进行运行(要修改只能创建新的镜像)。
Docker 把应用和依赖放在镜像文件里面,只有通过镜像才能生成容器。镜像生成的容器都是独立的,即使使用同一个镜像创建容器,容器里面的内容都是互独立的。所以我们一般也不在容器内进行修改,因为这些修改无法长期存储。
image 是二进制文件。实际开发中,一个 image 文件往往通过继承另一个 image 文件,加上一些个性化设置而生成。你可以在 Ubuntu 的 image 基础上,往里面加入 Apache 服务器,形成你的 image。
image 文件是通用的,一台机器的 image 文件拷贝到另一台机器,照样可以使用。一般来说,使用别人制作好的 image 文件,而不是自己制作,以节省时间。即使要制作,也应该基于别人的 image 文件进行加工,创建镜像,而不是从零开始。
如果拉取镜像配置失败,可能需要配置代理
拉取后的镜像如何使用,请参考对应镜像的文档,或者在该网站(https://hub-stage.docker.com)进行搜索对应的镜像,查看使用方式
容器
容器:从某一个镜像开始运行的点,并且容器之间互相独立。可以理解为从镜像运行起来。
Linux 有一种虚拟化技术:Linux 容器(Linux Containers,缩写为 LXC)。Linux 容器不是模拟一个完整的操作系统,而是对进程进行隔离。或者说,在正常进程的外面套了一个保护层。对于容器里面的进程来说,它接触到的各种资源都是虚拟的,从而实现与底层系统的隔离。
由于容器是进程级别的,相比虚拟机有很多优势。
- 启动快:容器里面的应用,直接就是底层系统的一个进程,而不是虚拟机内部的进程。所以,启动容器相当于启动本机的一个进程,而不是启动一个操作系统,速度就快很多。
- 资源占用少:容器只占用需要的资源,不占用那些没有用到的资源;虚拟机由于是完整的操作系统,不可避免要占用所有资源。另外,多个容器可以共享资源,虚拟机都是独享资源。
- 体积小:容器只要包含用到的组件即可,而虚拟机是整个操作系统的打包,所以容器文件比虚拟机文件要小很多。
总之,容器有点像轻量级的虚拟机,能够提供虚拟化的环境,但是成本开销小得多。
默认情况下,容器不会知道同一个机器上,任何其他线程或者容器的任何信息
一个镜像可以多次运行,产生不同的容器
volume
移除容器(container)后,该容器内对文件进行的任何操作都将丢失,Docker 会隔绝 container 内的所有操作。volume 能在选定容器和当前文件系统路径进行链接(映射)。
说直白点就是,可以决定 docker 从哪里(container 之外)获取,数据保存在哪里,可以保证数据不会丢失。
保证容器内数据的持续存储。
所以我们需要用 volume 将存储的数据(或者开发的内容)映射到操作系统的目录中来,如果没有 volume,修改的内容将会彻底丢失。
主要有两种 volume 类型
- volume mount:存储你的应用数据(docker 决定存储位置,让各个容器之间共享数据)
- bind mount:在本地和容器之间共享一个文件系统
如果指定的 volume 不存在,docker 默认会创建该 volume 的内容
- volume mount 如果没有内容,添加后默认内容将会是容器中目录内的内容
- bind mount 绑定后,如果绑定目录存在内容,会屏蔽容器内的目录(不会删除或者修改,但是也不能使用),使用本地文件夹代替 mount 的文件夹使用。
bind mount 关联的文件系统,如果在容器内运行,就是调用容器的 api 和功能,如果在本地运行,就是调用本地的功能。推荐应用场景:
- 在本地和容器间共享配置文件
- 提供源码或者在环境中构建
| Named volumes | Bind mounts | |
|---|---|---|
| 本地存放位置 | Docker 决定 | 自己决定 |
| 覆盖新容器的内容 | 是 | 否 |
网络
容器之间的沟通方式
网络默认为桥接模式,每一个容器都分配一个 IP 地址,可以通过 IP 地址进行访问,但和宿主机是隔离的
可以创建子网,同一个子网可以互相通信(ip,或容器的名字),跨子网不可以通信
每个容器都有固定的 ip,为容器添加网络有两种方式
- 方法一:通过镜像创建容器的时候
- 方法二:向已有的容器添加网络
[网络相关命令](./1.4-docker 命令.md)
日志
系统运行时,命令行输出的内容
# 获取容器日志 docker
docker container logs <container_id or container_name>
docker logs <container_id or container_name>
# 监控容器日志
docker container logs -f <container_id or container_name>
工程化
多容器应用
In general, each container should do one thing and do it well.
通常来讲,每个容器应该只做一件事,并且把事情做好,所以镜像需要功能相互独立。
- 独立容器可以简化前对前端,和数据库做不同的扩展。
- 分离的容器,能更好的隔离以及更新容器内容的版本。
- 运行多线程,将会需要进程管理器(增加容器启动和关闭复杂性)。容器只会使用一个进程。
Dockerfile
[2.3-dockerfile.md]
创建镜像必须使用 Dockerfile,Dockerfile 文档会包含一个用户在命令行调用去组装 image 的所有命令
包括从哪个镜像进行构建、工作目录等一系列内容
示例:
# Dockerfile 配置文件
# 格式:命令 内容
FROM node:18.4
COPY . /app # 将 . 当前目录的内容,都拷贝到 ./app 目录下
WORKDIR /app # 将 /app 设定为工作路径
RUN npm install --registry=https://registry.npm.taobao.org # 在大包为镜像时,执行命令
EXPOSE 3000 # 暴露的端口,会在 -p 使用到
docker-compose
如果将配置全在命令行里书写,不容易保存,且一次只能生成一个容器,修改和查找上下文也不方便。
以 docker-compose 来运行命令,可以解决上面的问题。即,通过一个 docker-compose.yml 文件生成多个容器。
[docker-compose 的使用](./2.1-docker compose.md)
自动化部署
使用 docker + jenkins 能实现代码提交到 github 后自动部署环境
docker login进行登录docker login -u username指定用户名称docker push username/image-name将镜像推送到 docker hub