Docker实践:构建React和Express项目
近期考虑了去学习如何部署自己的网站项目。根据网上的资料,决定先使用Docker+Nginx的组合来部署到本地上,之后再考虑部署到云端。
项目结构
我的项目前端是React,后端是Express、使用了Socket.io来实现实时通信、使用了MongoDB来存储数据。
Docker容器的话需要为每个服务创建一个容器,所以我需要创建三个容器:前端、后端、数据库。同时还要创建一个Nginx容器来作为反向代理。
Nginx是一个高性能的HTTP和反向代理服务器,也是一个IMAP/POP3/SMTP代理服务器。
那么反向代理是什么意思呢?通常情况下我们如果访问一个网站,浏览器会直接向服务器发送请求,服务器再返回数据给浏览器。而反向代理是指,浏览器发送请求给Nginx,Nginx再将请求转发给服务器,服务器返回数据给Nginx,Nginx再返回数据给浏览器。
这么做的目的是为了隐藏服务器的真实IP地址,提高安全性。因为用户只能向Nginx发送请求,而不能直接向服务器发送请求。
Dockerfile
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux机器上,也可以实现虚拟化。
为什么要使用Docker呢?因为Docker可以让开发者摆脱“在我的机器上可以运行”的问题。
应用能够在任何地方运行,而不用担心环境问题。这样就可以避免因为环境问题导致的bug,也可以避免因为环境问题导致的部署问题。
Docker的两个重要概念为镜像和容器。
镜像是一个只读的模板,可以想象为一个菜谱、详细列出了如何制作一道菜的步骤。就像你无法在菜谱上做菜一样,你也无法在镜像上做任何操作。
容器是镜像的一个实例,可以想象为一道菜。Docker(厨师)会根据镜像(菜谱)制作出容器(菜),并且可以对容器进行操作。
Dockerfile则是编写菜谱的过程。它是一个文本文件,包含了一条条的指令,每一条指令构建一层,从而构建出一个完整的镜像。
每个服务都需要一个Dockerfile来构建镜像。我的项目结构中暂且只有前端和后端,所以我需要创建两个Dockerfile、存放在这两个目录下。
1 | # client/Dockerfile |
1 | FROM node:20.11.0-alpine |
宿主机是指安装了Docker的机器,也就是我们的电脑。
Docker Compose
Docker Compose是一个用来定义和运行多容器Docker应用的工具。通过一个单独的docker-compose.yml
配置文件来配置应用的服务,然后使用docker-compose up
命令来从配置文件中构建、启动、管理整个应用。
因为我需要创建多个容器,所以我需要一个docker-compose.yml
文件来更好地管理这些容器。
在整个项目的根目录下创建一个docker-compose.yml
文件:
1 | # docker-compose.yml |
卷是一种数据持久化和数据共享的机制。它可以将宿主机的目录挂载到容器中,这样容器中的数据就可以持久化到宿主机上了。 即使容器被删除,宿主机上的数据也不会丢失。
网络定义了容器之间如何相互通信。每个网络都代表了一个独立的虚拟网络,容器可以连接到这个网络上,从而实现容器之间的通信。
bridge
类型会给容器分配一个IP地址,这样容器之间就可以通过IP地址相互通信。不同bridge
类型的网络是隔离的,即使是同一台宿主机上的容器也不能相互通信。
配置Nginx
Nginx的配置文件是nginx.conf
,这个文件需要放在docker-compose.yml
文件所在的目录下。
1 | server { |
MongoDB
Docker容器中的MongoDB服务不同于平常的MongoDB服务。通常服务端连接MongoDB的地址是localhost:27017
,但是在Docker容器中,要使用mongodb:27017
。
由于我的宿主机上已经有一个MongoDB服务在运行,所以我将容器的27017端口映射到了宿主机的28017端口。这样便可以避免端口冲突、使用宿主机上的MongoDB Compass直接连接localhost:28017
来管理容器中的MongoDB服务。
构建和运行
首先要构建整个应用:
1 | docker-compose build |
如果是想要构建单个服务,可以使用
docker-compose build 服务名
。服务名就是
docker-compose.yml
文件中定义的服务名。
然后运行整个应用:
1 | docker-compose up |
如果想要停止应用,使用
docker-compose down
。和
docker-compose build
一样,如果是想要运行/停止单个服务,可以使用docker-compose up/down 服务名
。
运行后就可以在浏览器中访问localhost
来查看应用了。
但是以上步骤只是在本地运行,并且我也没有使用开发环境。部署到云端、使用生产环境还需要更多的实践,之后再说。