前端研发需要知道的Docker

2023-11-27 22:46:18 浏览数 (3)

作为一名前端开发者,你可能会说,Docker和我有啥关系,我又用不到,因为它看起来更像是后端或者DevOps的领域。但实际上,Docker对前端开发同样有很多好处,比如:

  • Docker可以帮助你在本地环境中快速搭建和模拟生产环境。你知道,有时候在本地开发环境中一切正常,但代码一到生产环境就出问题了。使用Docker,你可以创建一个与生产环境尽可能接近的容器,这样就可以减少“在我机器上可是好的”这类问题。
  • 简化团队协作。想象一下,新同事加入项目,他们需要配置本地环境。传统方式可能需要安装各种依赖、设置数据库等等,这既费时又可能出错。但有了Docker,他们只需要拉取一个镜像,运行一个容器,所有环境就配置好了,可以立即开始工作,这极大的降低了新同事介入工作的成本。所以用上了Docker,你再也不用写一篇文档来告知如何配置本地开发环境,巴拉巴拉一大堆。
  • 前端项目通常会依赖后端API或数据库等服务,甚至有时候还需要配置代理来解决本地开发跨域的问题,这些真的很头疼。使用Docker Compose,你可以定义一个多容器的应用,其中包括前端应用、API服务器、数据库等,一键启动整个应用栈。

简单的理解Docker的原理

Docker是基于Linux容器(LXC)技术,但提供了更高层次的抽象和更简单的工具链。Docker使用容器来运行应用,容器是一种轻量级的、可执行的软件包,其中包含了运行某个软件所需的代码、运行时、系统工具、库和设置。这种实现与虚拟机不同,它们不需要包含操作系统的完整副本,而是与宿主机共享内核,只包含应用程序及其依赖,因此它们更加轻量级和快速。Docker使用镜像来创建容器,镜像是一个轻量级、可移植、自给自足的软件运行环境的模板。你可以把它想象成一个快照,任何时候基于这个镜像启动的容器,都会是一个一模一样的环境。

Docker的工作流程通常包括构建、运输和运行。你首先在本地构建一个Docker镜像,然后可以将它推送到Docker Hub或其他注册中心,最后在任何安装了Docker的机器上运行这个镜像,就可以启动一个一致的容器环境。

就此打住,废话不宜过多,但是考虑到前端研发同学可能有些并没接触过docker,还是有点点必要科普一下。

基于Docker开发前端应用

学以致用,假社我们就是奔着统一环境的目的来的,解决新同学加入团队需要配置一堆本地开发环境的痛点,此时我们采取使用Docker的开发方式是如何的呢?

再次假设,如我们需要使用react来开发前端应用,此时,我们的第一步,依然是创建一个 react应用,npx create-react-app my-app-docker完了之后,随后就有一些不同了,我们要多追加一个Docker描述文件Dockerfile,其内容如下,然后竟就是打包镜像,启动容器,剩下的开发体验和本地启动服务完全一样。

代码语言:javascript复制
# 使用官方Node.js作为基础镜像
FROM node:latest

# 设置工作目录
WORKDIR /app

# 复制package.json和package-lock.json(如果有)
COPY package*.json ./

# 安装项目依赖
RUN npm install

# 复制项目文件到工作目录
COPY . .

# 暴露容器的端口号
EXPOSE 3000

# 运行前端服务
CMD ["npm", "start"]

随后,我们执行 docker build -t my-app-docker .来打一个镜像出来。这个命令的解析是:

  • docker build: Docker CLI命令,用于构建Docker镜像。
  • t my-frontend-appt标志指定要创建的镜像的名称(在这里是my-frontend-app)。这个名称可以在后续的docker run命令中使用。
  • .: 指定Dockerfile所在的路径。在这个例子中,.表示当前目录。

执行的过程如下所示。

打镜像完毕之后,我们可以看到Docker的管理段中,Images里面会多一个镜像,就是我们刚才打的镜像。

此时,有了这个镜像,我们就可以启动这个镜像了,你可以直接使用界面的方式启动,就是点击那个play按钮,出来后:

这里面有一些配置参数,映射端口号容器名字映射目录环境变量等。但是我更加推荐你使用命令的方式来,表示用习惯了会更加快。

启动镜像

docker run -p 3000:3000 my-frontend-app,这个命令的含义如下:

  • docker run: 运行一个Docker容器的命令。
  • p 3000:3000p标志将容器内部的端口映射到宿主机的端口。3000:3000的意思是将容器的3000端口映射到宿主机的3000端口。
  • my-frontend-app: 这是你之前构建的镜像的名称。

好了之后,你应该可以在 http://localhost:3000 看到你的react应用了。

如何实现文件同步呢?

我们不可能在开发的过程中变更一样代码,就打一个镜像,这样做效率也太低了,有什么办法吧本地变更的文件同步到容器中呢?答案就是我们使用界面方式启动时,里面看到的那个 Volumes。命令来执行就是:

docker run -p 3000:3000 -v $(pwd):/app my-frontend-app

-v $(pwd):/app-v标志用于挂载卷。$(pwd)是当前工作目录的路径,/app是容器内的路径。这意味着你的工作目录将被挂载到容器的/app目录,从而实现文件同步。

我们试着改变一下本地的文件,从命令行里面可以看到,容器的环境中同步到了变化,开始编译了。

这就意味着,你的本地的变更,将会同步反应到容器中,实现本地代码变更,热更新到界面上,和本地开发无任何不同。

镜像太大,有没有办法变小?

我们可以使用比较小的基础镜像,以改用node:alpine,因为Alpine Linux版本的镜像通常更小。

可以看到,我们的镜像直接就小了一半。从1.64G压缩到了 735M。有人会讲了,这依然很大啊,还有办法更小吗?

所以,除此之外,还有更加进一步的优化办法吗?当然,方法还不仅仅如此,比如,我们还可以尝试多阶段构建,因为,react最终的产物就是一堆html css js。所以,我们这么玩,分两个阶段。

代码语言:javascript复制
# 第一阶段:构建
FROM node:alpine as build-stage
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# 第二阶段:运行
FROM nginx:alpine
COPY --from=build-stage /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

但是,我们发现,这个似乎只建议在生成环境打镜像的时候用,开发的时候,并不合适,因为我们要做目录映射,要做热更新。

更上一层楼

如果,我们需要依赖某几个后端服务,怎么办呢?答案是,我们可以使用**Docker Compose,**这个compose的意思就可以简单的理解为组合。比如一个简单的:

代码语言:javascript复制
version: '3'  # 指定了使用的Compose文件版本
services:  # 定义了多个服务(容器),可以相互协作
  frontend:  # 定义了名为“frontend”的服务
    build: .  # 指定Dockerfile所在的目录(当前目录),用于构建镜像
    ports:
      - "3000:3000"  # 将容器的3000端口映射到宿主机的3000端口
    volumes:
      - .:/app  # 将当前目录挂载到容器的/app目录,实现代码同步
    depends_on:
      - backend  # 表示“frontend”服务依赖于“backend”服务

  backend:  # 定义了名为“backend”的服务
    image: "my-go-service"
		ports:
		  - "5000:5000"  # 将容器的5000端口映射到宿主机的5000端口,这样你就可以通过宿主机的端口访问后端服务。

这个docker-compose.yml文件定义了两个服务:一个前端服务和一个后端服务。前端服务会构建一个Docker镜像(基于当前目录下的Dockerfile),注意,因为我们frontend这个服务里面有build字段,所以才会构建,并且将宿主机的当前目录挂载到容器内部的/app目录,以便实现实时同步。后端服务则直接使用一个已经存在的镜像,他不需要构建。一个docker-compose.yml可以只方一个服务都是OK的。

docker-compose up 命令到底做了些啥

简单的讲,当你在包含docker-compose.yml文件的目录中运行docker-compose up命令时,Docker Compose会执行以下操作:

  1. 读取配置:Docker Compose首先读取docker-compose.yml文件,解析里面定义的服务、网络、卷等配置。
  2. 构建镜像:对于那些需要构建的服务(如我们的例子里面,frontend),Docker Compose会根据Dockerfile构建镜像。构建的镜像会被存储在本地的Docker镜像库中。
  3. 拉取镜像:对于直接指定了镜像名称的服务(如backend),如果本地没有这个镜像,Docker Compose会从Docker Hub或其他指定的镜像仓库拉取镜像,本地有当然就直接用本地的了。
  4. 创建网络:Docker Compose会创建一个默认的网络,使得定义在docker-compose.yml文件中的服务可以互相通信。
  5. 启动容器:Docker Compose会根据配置启动服务对应的容器。如果有depends_on配置,Docker Compose会先启动依赖的服务。
  6. 应用卷映射:对于定义了卷映射的服务,Docker Compose会将指定的宿主机目录或文件挂载到容器内的相应位置。
  7. 端口映射:Docker Compose会将容器的端口映射到宿主机的端口,使得可以从宿主机访问容器内部的应用。
  8. 日志输出:默认情况下,Docker Compose会捕获并输出所有容器的stdout和stderr到终端,让你可以实时看到输出。
  9. 运行状态:除非你在命令后添加了d参数来让服务在后台运行,否则Docker Compose会保持在前台,并且当你按下Ctrl C时停止所有服务。

通过这个过程,Docker Compose简化了多容器Docker应用的管理,你不需要手动执行一系列的docker builddocker run命令来启动你的应用。所有的配置都可以在docker-compose.yml文件中声明,使得整个过程更加简洁。

因此,我们看到,实际上在前端开发上,也可以使用docker,docker这个技术针对的不仅仅是后端各种服务,他更加像是一种思想,万物皆容器。

我正在参与2023腾讯技术创作特训营第三期有奖征文,组队打卡瓜分大奖!

0 人点赞