type
status
date
slug
summary
tags
category
icon
password

1. 前言

曾几何时想到部署那不是运维的工作吗?
notion image
但最近在尝试部署自己的应用,docker 这一环终究是逃不过。这个技术对于前端来说,还是稍微有一点陌生。但如果你曾经也和我一样把台式电脑当作自己的游戏机,用光盘安装过单机游戏,然后打开游戏玩到“昏天黑地”,那么看完这一篇文章,你一定会使用 docker。

2. 什么是 docker?

在说 docker 之前,我们需要了解虚拟机。虚拟机说得通俗一点,就是依托本地物理机的环境构建出的另一台电脑:
Schematic representation of a hosted hypervisor. The virtualization software allocates a virtual contingent of hardware resources provided by the host system (CPU time, RAM, disk space, and peripherals) to each VM.
Schematic representation of a hosted hypervisor. The virtualization software allocates a virtual contingent of hardware resources provided by the host system (CPU time, RAM, disk space, and peripherals) to each VM.
虚拟机
虚拟机
docker
docker
与虚拟机相比,docker 无需虚拟硬件环境然后再跑一个操作系统,它是一种轻量级的虚拟化,这种虚拟化技术称为容器化
docker 利用操作系统的核心功能,如 Linux 的命名空间、控制组(cgroups)等特性,来创建独立的、隔离的运行环境,这个环境称为容器
每个容器都可以运行一个或多个应用程序,并提供了与物理计算机相似的隔离性和资源管理能力,可以在不同的计算机或操作系统上运行应用程序,不必担心环境差异或依赖项冲突。
总结一下就是:docker 启动的容器共用宿主机的内核,不同容器之间是完全独立的。这样一来就可以保证需要部署的应用始终处于统一的环境配置下,方便持续集成和持续交付。另外,还可以利用这个特性创建统一的开发环境。

3. Docker 的组成

3.1 docker 的感性理解

docker 作为一个工具,它的三件套是:
  • Dockerfile
  • image(镜像)
  • container(容器)
所谓 Dockerfile 就是某个环境的设计稿或蓝图,image 是依照 Dockerfile 刻录下来的镜像,用 image 就可以启动一个或多个独立环境,也就是 container(容器)。
如果非要类比成现实生活中的 🌰,大概是这样:
男生都有热爱游戏的人生阶段。那时候家里换了新电脑,别提多兴奋,我立马找到小伙伴东拼西凑出了一包游戏光碟,什么 CS1.5,CS1.6,魔兽争霸、星际争霸,仙剑奇侠传三、仙剑客栈、三国志11、侠盗飞车……应有尽有。之后,小伙伴们高高兴兴地团坐在一起,我按下主机上的 open 键打开了光驱,拿着 CS 1.5 的游戏光碟扣了进去。
close-我的电脑-F盘-双击-选择安装目录-安装,光碟在光驱中疯狂转动了一阵,一气呵成,双击运行 CS 1.5,是兄弟就在沙漠地图等着我。
当然,在家里联网以后,我就从游侠网上直接下载游戏安装包了,主打一个快乐。
在这段童年趣事中,那一张一张的游戏光碟就是不同的 image,双击运行(run)起来的 CS1.5 就是一个 container。而不同游戏厂商开发出来的游戏设计就是 Dockerfile,根据这份 Dockerfile 将文件刻录进光碟就是 image 的构建(build)。至于 CS1.5 和 1.6 或仙剑奇侠传一和三,这种游戏版本的区别,可以理解为不同版本(tag)的 image。从游侠网直接下载安装包就是拉取 image(pull),而游侠网作为一个游戏平台就是 docker hub —— docker 官方的镜像中心。

3.2 docker 使用流程

docker 流程
docker 流程
如果将上述流程整理出来,大概是这样的:
  1. 准备环境:首先,需要在计算机上安装 docker。这类似于当初安装游戏的过程。
    1. docker —version
    2. docker info
  1. 下载/构建镜像:类似于从游侠网下载游戏安装包,docker 使用镜像来构建容器。镜像是一个预先配置好的文件,其中包含了一个完整的应用程序及其依赖项。可以从 Docker Hub 等镜像仓库中搜索并下载适合需求的镜像。或者自己准备一个刻录机,自己刻录游戏,那这就是构建镜像。
    1. docker pull <image>
    2. docker build -t <image> <path>
  1. 创建容器:一旦下载了所需的镜像,就可以使用 docker 命令创建容器。容器是基于镜像创建的运行实例,类似于当初安装的游戏。我们可以指定容器的各种参数,例如端口映射、文件挂载等。
    1. docker run -d --name <your_contianer_name> -p 8080:80 -v $(pwd):/app <image>
  1. 运行应用程序:一旦容器创建完成,就可以使用 docker 命令来启动容器并运行应用程序。就像您当初双击运行游戏一样,docker 会启动容器并运行您所需的应用程序。
    1. docker exec -it <container> <command>

3.3 docker 常用指令

容器管理
  • docker run <image>:运行一个新的容器
  • docker start <container>:启动一个已停止的容器
  • docker stop <container>:停止一个正在运行的容器
  • docker restart <container>:重启一个容器
  • docker rm <container>:删除一个容器
  • docker ps:列出当前正在运行的容器
  • docker ps -a:列出所有容器,包括停止的容器
镜像管理
  • docker images:列出本地的镜像
  • docker pull <image>:下载一个镜像
  • docker push <image>:将一个镜像推送到远程仓库
  • docker build -t <image> <path>:根据 Dockerfile 构建一个镜像
  • docker rmi <image>:删除一个本地的镜像
日志和输出
  • docker logs <container>:查看容器的日志
  • docker exec -it <container> <command>:在正在运行的容器中执行命令
  • docker cp <container>:<path> <local_path>:将容器中的文件复制到本地
网络和端口
  • docker network ls:列出 Docker 网络
  • docker network create <network>:创建一个新的 Docker 网络
  • docker network connect <network> <container>:将容器连接到指定的网络
  • docker port <container>:显示容器的端口映射
数据管理
  • docker volume ls:列出 Docker 卷
  • docker volume create <volume>:创建一个新的 Docker 卷
  • docker volume inspect <volume>:查看卷的详细信息
  • docker volume rm <volume>:删除一个 Docker 卷
其他常用指令:
  • docker info:显示系统信息
  • docker logs <container>:获取容器的 log 信息
  • docker inspect <container>:显示一个容器的具体配置信息

4. 部署前端项目

现在,让我们小试牛刀。
安装 docker 去 docker 官网安装,设置国内镜像源加速直接搜索教程,这两步我就略过了。
举个 🌰,如果我想要把前端项目部署到本地,我该怎么做?

4.1 准备前端项目源码

用 vite 火速创建一个 react + ts 项目:
创建完成后,打包项目代码:npm run build ,得到 dist 打包文件。

4.2 添加 nginx.conf

部署需要用到 nginx 服务器,这是一个高性能的开源Web服务器和反向代理服务器,它在处理高并发、负载均衡等方面表现卓越。下面是 nginx.conf 文件,属于 nginx 的主要配置文件,启动 nginx 服务后,将会根据这个文件来确定如何处理传入的请求和响应:

4.3 添加 Dockfile

在项目根目录下新建文件 Dockerfile,内容如下:
  • FROM nginx:stable-alpine3.17:这个指令指定了基础镜像,使用了名为 nginx:stable-alpine3.17 的基础镜像(优先从本地获取,如果本地没有,就从 docker hub 上拉取)。这个基础镜像是一个带有 nginx 的 Alpine Linux 镜像(Alpine 版本的镜像更加轻量),版本为 3.17。
  • COPY dist /usr/share/nginx/html:这个指令将当前目录下的 dist 目录中的内容复制到docker 镜像中的 /usr/share/nginx/html 目录下(这是 nginx 的默认的 html 目录)。
  • COPY nginx.conf /etc/nginx/nginx.conf:这个指令将当前目录下的 nginx.conf 文件复制到 docker 镜像中的 /etc/nginx/nginx.conf 文件中。这个文件是 nginx 的配置文件,通过复制到镜像中,可以在运行容器时使用自定义的 nginx 配置。
nginx:stable-alpine3.17 就是基础镜像,其他常用的基础镜像还有 ubuntunodenginxpostgres 等等,这些镜像是推荐提前就拉取到本地的,以后当本地构建镜像时,一旦用到就会用本地的,无需重新拉取远程的镜像。
现在拉取 nginx:stable-alpine3.17:

4.4 构建镜像

文件结构
文件结构
现在准备工作就绪了,让我们开始构建镜像:
  • -t 指定 image 的名字(vite-web),后面可以用冒号指定标签(v1),默认是 latest
  • . 表示 Dokcerfile 文件所在路径,docker 会在这个目录下找到 Dockfile,然后以此来构建镜像(这里表示当前路径)
构建成功
构建成功
构建完成,通过指令 docker images 可以看到 vite-web:v1 镜像已经在 image 的列表中了。
镜像列表
镜像列表

4.5 启动容器

镜像完毕后,使用这个镜像来启动容器:
  • -d 参数表示以后台模式运行容器,即容器将在后台运行而不阻塞终端。
  • --name my-web-1 参数指定容器的名称为 "my-web-1",这个名称可以用来唯一标识容器。
  • -p 8081:80 参数将容器的 80 端口映射到主机的 8081 端口,这样可以通过主机的 8081 端口访问容器中的应用程序。(类似的 -v 参数也是左边是主机、右边是容器环境)
  • vite-web:v1 是要运行的容器镜像的名称和标签。
执行命令,看一下正在运行的容器列表:
notion image
通过 curl 指令来查看网页连接情况:
测试网页连接情况
测试网页连接情况
再打开网页看看:
notion image
有的时候,想要查看容器的日志,比如看看为什么没有运行起来、为什么报错了、谁来访问过了等等。用这个指令:
容器 my-web-1 的日志
容器 my-web-1 的日志
到此,前端本地部署成功!

4.6 自动化部署流程

在上面的整个流程中,不管是镜像构建还是容器运行,都是手动去敲命令的,然而,重复的工作都可以被优化。现在使用 sh 脚本来自动化执行整个部署流程。
sh 脚本文件一般放在 bin 目录下,在 bin 目录下新建文件 setup_for_host.sh 文件:
写好后,把之前运行的 my-web-1 容器删除,因为占用了本机的 8080 端口,和脚本里的 host_port 会冲突:
删除后,在根目录下执行脚本:
部署流程自动化
部署流程自动化
自动化部署脚本成功了!!!

4.7 小结

用一幅图来总结这一部分内容:
本地部署前端项目
本地部署前端项目
镜像启动出一个容器环境,把容器环境中的 nginx 服务器需要的两个文件从宿主机上拷贝过来,然后把 80 端口映射到宿主机的 80 端口,在宿主机上即可访问网页。

5. 部署 Node.js 应用

掌握了前端项目的本地部署后,Node 应用如何部署?

5.1 准备后端服务源码

node.js 安装就略过了。
直接用命令行开干:
server.js 内容如下:
在 package.json 文件中添加启动脚本:
notion image
运行 npm run start 后,使用 curl 查看回应,一切正常:
notion image

5.2 添加 .dockerignore 和 Dockfile

express 包用到了 node,本地的 node_modules 不需要拷贝进 docker,所以要用到一个很像 .gitignore 的文件 —— .dockerignore,用来忽略相应文件,.dockerignore 文件内容如下:
在项目根目录下新建文件 Dockerfile,内容如下:

5.3 构建镜像 + 启动容器

这一步和前端部署章节是一样的。
构建镜像:
构建了一个叫做 express-app 的 image,如果不加冒号和 tag 号,那么构建出的镜像默认就是 latest 版本。
启动容器:
用 express-app 启动一个叫做 my-express-app 的 express 应用容器。
通过 curl 指令来查看网页连接情况:
notion image
连接正常!
如果想停掉这个运行的服务就执行 docker stop my-express-app ,如果想再次启动就执行 docker start my-express-app
Node 应用的部署也搞定了!
至于自动化部署,按照前端自动化部署脚本照猫画虎即可,这里不多赘述了~

5.4 进入容器

如果想要进入容器看看,那么执行:
输入 whoami 可以看到当前用户是 root
whoami
whoami
如果没有在 Dockerfile 中设置权限,那么默认都会使用 root,这是一个潜在的问题,一般生产环境不会直接使用 root 去部署服务,关于这一点先挖个坑。
输入 exit 回车即可退出容器操作。

6. 镜像推送

现在我们前后端的镜像都有了(vite-web 和 express-app),推送到仓库去,然后测试工程师就可以从测试环境、生产环境拉取代码进行测试了。一般来说,公司都会搭建自己的 docker 镜像仓库,这里以 docker hub 为例(注册略):

6.1 docker 登录

第一步、登录 docker hub:
docker 登录成功
docker 登录成功

6.2 tag 标签设置

第二步、给镜像打上标签:
注意:username 必须是你的用户名,不能乱填。

6.3 推送到镜像仓库

最后推动到仓库:
镜像推送
镜像推送
之后,在 docker hub 上就能看到刚刚推送的镜像了:
你的镜像仓库
你的镜像仓库

7. 总结

到这里,基本上就可以掌握 docker 的基础使用以及如何在本地部署项目了,基本流程掌握好就可以:
  • Dockerfile
  • docker build 或 docker pull
  • docker run
  • docker push
当然还有其他的 docker 指令,大家可以自己琢磨琢磨。另外,其实部署的内容还有很多很多。比如如何通个网将前后端、数据库联合起来、如何做数据持久化、如何做 CI / CD、如何部署到云服务器,甚至是放弃 docker,使用 serverless 部署,暂且挖个坑……
 
以上,如有谬误,还请斧正,感谢您的阅读~
 
参考:
  1. Virtual Machines:https://www.ionos.com/digitalguide/server/know-how/virtual-machines/
  1. Docker — 从入门到实践:https://docker-practice.github.io/zh-cn/
  1. Dockerizing a Node.js web app:https://nodejs.org/en/docs/guides/nodejs-docker-webapp
  1. docker docs:https://docs.docker.com/get-started/overview/
 
前端工程师也应该了解的 docker composeRuby on Rails 快速入门
Eric 见嘉
Eric 见嘉
Less is more.
公告
type
status
date
slug
summary
tags
category
icon
password
💭
合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。

关于我
土木转行的前端开发工程师,陆续分享技术干货。
联系我
微信公众号:见嘉 Being Dev