Docker Compose 部署前后端分离应用

部署前后端分离应用

容器化 Abp 应用

关于 Abp 应用的容器化,其实和普通的 ASP.NET Core 应用差不多,大家可以参考我此前的文章

唯一需要注意的是:因为 Abp 解决方案中有多个项目,在 publish 过程中需要手动指定启动项目,例如:

# 其余内容请参考上述文章
# 修改 RUN dotnet publish -c Release -o /app 为以下内容
RUN dotnet publish ./src/YourProjectName.Web.Host/YourProjectName.Web.Host.csproj -c Release -o /app

使用 sql 文件应用迁移

在使用 EF Core 进行 Code First 开发的时候,我们往往都习惯在 VS 的控制台中使用Update-Database完成迁移。但在实际部署过程中,考虑开发环境可能无法直接与部署所用主机相连,我们可以通过导出 sql 文件的形式来完成迁移。

在解决方案的根目录下打开命令行:

dotnet ef migrations script -p .\src\YourProjectName.EntityFrameworkCore\ -o .\init.sql

然后,将该 init.sql 文件挂载到 mysql 的镜像的初始化目录当中:

version: "3"

services:
  mysql:
    # ...
    volumes:
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql

这样,就会在 mysql 容器启动时,自动完成迁移。

使用外部网络桥接数据库

在我们的 API 应用中,会在启动阶段检测数据库中是否正确配置了基础信息,这就带来一个棘手的问题:当所用数据库比如说 MySQL,也是通过同一个 Docker Compose 部署的时候,会有启动延迟,从而使得数据库还未来得及应用迁移(Apply Migrations),即便在配置文件中配置了depends_on也无法避免。

depends_on只影响容器启动的顺序,而此处 MySQL 的启动延迟是在容器启动后发生的。

在此前,我一直是通过脚本或者额外的代码来为 API 应用增添启动延迟重试的功能,但显然这对生产环境来说并不合适。

其实,我们可以来分析一下几个要求:

  1. MySQL 必须在 API 应用启动前,完成初始化或迁移。
  2. 不应为此给 API 应用引入额外的逻辑。
  3. API 应用的更新不应该影响数据库。

所以,最终还是决定将数据库独立出来,单独用一个 Docker Compose 来进行部署,可这也带来一个新的问题:API 应用无法确定数据库所在的子网 IP,或者说两者甚至不在同一子网中。

那么,自然得想办法将数据库重新加入 API 应用所在的子网,通过查找资料,Docker Compose 已经为我们提供了这一功能,即使用外部网络。

这里又可以多说一句,在我们使用 Docker Compose 部署的时候,其默认会为我们创建一个子网,并将我们的定义的服务添加到该子网中。而这个网络是直接由 Docker Compose 管理的,在up时创建,在down时销毁,因此不符合我们需要将多个 Docker Compose 定义的服务加入同一子网的要求。

手动创建一个虚拟子网:

docker network create xxx

在配置文件中定义该网络,并将服务分别添加到该网络:

# db.yml
version: "3"

services:
  mysql:
    # ...
    networks:
      - xxx

networks:
  # 定义该网络为外部网络
  xxx:
    external: true

# 同理
# docker-compose.yml
version: "3"

services:
  api:
    # ...
  networks:
    - xxx

networks:
  xxx:
    external: true

然后,在部署的时候,我们只需要在第一次部署时,先等等 MySQL 已经完成初始化,再启动 API 应用即可。且对此后的 CI/CD 过程,我们也只需要关注 API 应用镜像的更新(需要修改数据库表结构除外)。

使用 Nginx 部署 SPA 应用

我们的前端都是以 SPA 应用来构建的,也就是说只需发布静态文件即可。这里我们就使用 Nginx 作为 Web 服务器。

值得注意的也就以下三点:

  1. 挂载 Web 根目录和配置文件
  2. 开启反向代理
  3. 开启伪静态

挂载目录和文件已经是老生常谈了,这里就不再赘述,在 docker-compose.yml 中配置以下两行即可:

version: "3"
services:
  web:
    # ...
    volumes:
      - ./html:/usr/share/nginx/html
      - ./nginx.conf:/etc/nginx/conf.d/default.conf

接下来是开启反向代理,这里我们所请求的 API 都是以/api为前缀的相对路径,因此只需要在 nginx.conf 中配置:

server {
  # ...
  location /api {
    proxy_pass http://api;
    proxy_set_header   X-Forwarded-Proto $scheme;
    proxy_set_header   Host              $http_host;
    proxy_set_header   X-Real-IP         $remote_addr;
  }
}

可能细心的人有发现这里将请求代理给了 api 这个域名,其实也就是我们所定义的 api 服务。那为了让这种写法有效,自然别忘了将 web 服务和 api 服务添加到同一子网,可以是之前的外部子网,或者再新建一个內部子网也行。

配置到这里,其实已经是可以用了,但在你刷新页面的时候不时会出现 404 错误。这是因为 SPA 应用的路由并不对应真正文件的路径,我们需要将对应的请求指向我们真正的文件,也就是伪静态。

例如,你的应用发布在 Web 根目录下,其主页面名为 index.html,可以如下配置:

server {
  # ...
  location / {
    try_files $uri $uri/ /index.html;
  }
}

结语

最终,你所有的配置文件应该如下:

docker-compose.yml

version: "3"

services:
  api:
    container_name: xxx_api
    image: xxx:api
    ports:
      - "21021:80"
    volumes:
      # 这里映射日志目录
      - ./App_Data:/app/App_Data
    environment:
      - ConnectionStrings:Default=server=mysql;userid=root;pwd=xxx;port=3306;database=xxx;Charset=utf-8;
      # 跨域控制
      - App:ServerRootAddress=http://xxx.xxx:21021
      - App:ClientRootAddress=http://xxx.xxx:8000
      - App:CorsOrigins=http://xxx.xxx:8000,http://xxx.xxx:21021
    networks:
      - xxx
  web:
    container_name: xxx_web
    image: nginx
    ports:
      - "8000:80"
    volumes:
      - ./html:/usr/share/nginx/html
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    networks:
      - xxx

networks:
  xxx:
    external: true

db.yml

version: "3"

services:
  mysql:
    container_name: xxx_mysql
    image: mysql:8.0
    ports:
      - "3306:3306"
    environment:
      - MYSQL_ROOT_PASSWORD=xxx
      - MYSQL_DATABASE=xxx
    volumes:
      - ./mysql:/var/lib/mysql
      - ./charset.cnf:/etc/mysql/conf.d/charset.cnf
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    networks:
      - xxx

networks:
  xxx:
    external: true

nginx.conf

server {
    listen 80;
    # gzip config
    gzip on;
    gzip_min_length 1k;
    gzip_comp_level 9;
    gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
    gzip_vary on;
    gzip_disable "MSIE [1-6]\.";

    root /usr/share/nginx/html;

    location / {
        try_files $uri $uri/ /index.html;
    }
    location /api {
        proxy_pass http://api;
        proxy_set_header   X-Forwarded-Proto $scheme;
        proxy_set_header   Host              $http_host;
        proxy_set_header   X-Real-IP         $remote_addr;
    }
}

转载于:https://www.cnblogs.com/yiluomyt/p/10608112.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要在EC2上使用Docker Compose部署前后端分离项目,您可以按照以下步骤操作: 1. 在EC2实例上安装DockerDocker Compose。 - 运行以下命令安装Docker: ```shell sudo apt update sudo apt install docker.io ``` - 安装完Docker后,您可以运行以下命令安装Docker Compose: ```shell sudo apt install docker-compose ``` 2. 在EC2实例上创建一个项目文件夹,并将前端和后端代码分别放入两个子文件夹中。 3. 在项目文件夹中创建一个名为 `docker-compose.yml` 的文件,并使用以下示例配置进行编辑: ```yaml version: '3' services: frontend: build: ./frontend ports: - 80:80 backend: build: ./backend ports: - 8000:8000 ``` 这个示例配置了两个服务,一个是前端服务(使用端口80),另一个是后端服务(使用端口8000)。您可以根据自己的项目需求进行修改。 4. 在项目文件夹中打开终端,并使用以下命令构建和启动Docker容器: ```shell sudo docker-compose up -d ``` 这将使用Docker Compose根据配置文件构建和启动两个容器,分别运行前端和后端应用程序。 5. 确保EC2实例的安全组配置允许通过所需的端口访问您的应用程序。 现在,您的前后端分离项目应该已经成功部署在EC2实例上了。您可以使用实例的公共IP地址或域名加上相应的端口访问您的应用程序。 请注意,这只是一个简单的示例配置,实际部署过程可能会根据您的项目需求有所不同。您可能需要进一步配置数据库、网络等方面,以适应您的项目。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值