使用 Docker 和 Kubernetes 将 React JS 和 .NET Core 应用容器化

发布:2024-09-24 13:16 阅读:46 点赞:0

一. 简介

本文将创建一个使用 .NET Core Web API 和 React JS 网页表单的示例产品应用程序后端。我们还将借助 Docker 和 Kubernetes 对其进行容器化。

二. 议程

  1. 示例产品应用程序后端(.NET Core Web API)
  2. 示例产品应用程序前端(React JS)
  3. 应用程序的 Docker 文件
  4. 容器化应用程序

三. 先决条件

  • Visual Studio
  • Docker Desktop(包含 Kubernetes)
  • NPM
  • .NET Core SDK
  • React JS

四. 示例产品应用程序:后端(.NET Core Web API)

步骤 1:创建新的产品管理 .NET Core Web API

在 Visual Studio 中,创建一个新的 ASP.NET Core Web API 项目。

步骤 2:安装 NuGet 包

安装以下 NuGet 包以支持内存数据库:

NuGet 包

步骤 3:添加产品类

在 Entities 文件夹中添加 Product 类。

namespace ProductManagementAPI.Entities
{
    public class Product
    {
        public int Id { getset; }
        public string Name { getset; }
        public decimal Price { getset; }
    }
}

步骤 4:创建 AppDbContext 类

在 Data 文件夹中创建 AppDbContext 类,并使用内存连接和 DB 集合属性。

using Microsoft.EntityFrameworkCore;
using ProductManagementAPI.Entities;

namespace ProductManagementAPI.Data
{
    public class AppDbContext : DbContext
    {
        public DbSet<Product> Products { getset; }

        public AppDbContext(DbContextOptions<AppDbContext> options)
            : base(options)

        {
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
                optionsBuilder.UseInMemoryDatabase("InMemoryDb");
            }
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            // 可选择在此配置实体映射
        }
    }
}

步骤 5:添加产品仓库

在 Repositories 文件夹中添加 IProductRepository 接口和 ProductRepository 实现。

IProductRepository

using ProductManagementAPI.Entities;

namespace ProductManagementAPI.Repositories
{
    public interface IProductRepository
    {
        Task<List<Product>> GetAllProductsAsync();
        Task<Product> GetProductByIdAsync(int id);
        Task AddProductAsync(Product product);
        Task UpdateProductAsync(Product product);
        Task DeleteProductAsync(int id);
    }
}

ProductRepository

using Microsoft.EntityFrameworkCore;
using ProductManagementAPI.Data;
using ProductManagementAPI.Entities;

namespace ProductManagementAPI.Repositories
{
    public class ProductRepository : IProductRepository
    {
        private readonly AppDbContext _context;

        public ProductRepository(AppDbContext context)
        {
            _context = context;
        }

        public async Task<List<Product>> GetAllProductsAsync()
        {
            return await _context.Products.ToListAsync();
        }

        public async Task<Product> GetProductByIdAsync(int id)
        {
            return await _context.Products
                .AsNoTracking()
                .FirstOrDefaultAsync(p => p.Id == id);
        }

        public async Task AddProductAsync(Product product)
        {
            if (product == null)
            {
                throw new ArgumentNullException(nameof(product));
            }

            _context.Products.Add(product);
            await _context.SaveChangesAsync();
        }

        public async Task UpdateProductAsync(Product product)
        {
            if (product == null)
            {
                throw new ArgumentNullException(nameof(product));
            }

            _context.Entry(product).State = EntityState.Modified;
            await _context.SaveChangesAsync();
        }

        public async Task DeleteProductAsync(int id)
        {
            var product = await _context.Products.FindAsync(id);
            if (product == null)
            {
                throw new KeyNotFoundException("Product not found.");
            }

            _context.Products.Remove(product);
            await _context.SaveChangesAsync();
        }
    }
}

步骤 6:创建产品控制器

创建一个新的产品控制器,定义不同的操作方法。

using Microsoft.AspNetCore.Mvc;
using ProductManagementAPI.Entities;
using ProductManagementAPI.Repositories;

namespace ProductManagementAPI.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class ProductsController : ControllerBase
    {
        private readonly IProductRepository _repository;

        public ProductsController(IProductRepository repository)
        {
            _repository = repository;
        }

        [HttpGet]
        public async Task<IActionResult> GetAllProducts()
        {
            var products = await _repository.GetAllProductsAsync();
            return Ok(products);
        }

        [HttpGet("{id}")]
        public async Task<IActionResult> GetProductById(int id)
        {
            var product = await _repository.GetProductByIdAsync(id);
            if (product == null)
            {
                return NotFound();
            }
            return Ok(product);
        }

        [HttpPost]
        public async Task<IActionResult> AddProduct([FromBody] Product product)
        {
            if (product == null)
            {
                return BadRequest();
            }
            await _repository.AddProductAsync(product);
            return CreatedAtAction(nameof(GetProductById), new { id = product.Id }, product);
        }

        [HttpPut("{id}")]
        public async Task<IActionResult> UpdateProduct(int id, [FromBody] Product product)
        {
            if (product == null || id != product.Id)
            {
                return BadRequest();
            }
            await _repository.UpdateProductAsync(product);
            return NoContent();
        }

        [HttpDelete("{id}")]
        public async Task<IActionResult> DeleteProduct(int id)
        {
            await _repository.DeleteProductAsync(id);
            return NoContent();
        }
    }
}

步骤 7:注册服务并配置中间件

在 Program.cs 中注册服务并配置中间件。

using Microsoft.EntityFrameworkCore;
using ProductManagementAPI.Data;
using ProductManagementAPI.Repositories;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddScoped<IProductRepository, ProductRepository>();
builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseInMemoryDatabase("InMemoryDb"));
builder.Services.AddCors(options => 
{
    options.AddPolicy("CORSPolicy", builder => builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
});
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

app.UseCors("CORSPolicy");
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

步骤 8:运行应用程序

最后,运行应用程序并使用 Swagger UI 执行不同的 API 端点。

Swagger 用户界面

五. 示例产品应用程序:前端(React JS)

让我们创建一个客户端应用程序,使用 React JS 并消费上述 API 端点。

步骤 1:创建新的 React JS 应用程序

使用以下命令创建新的 React 应用程序。

npx create-react-app react-netcore-crud-app

步骤 2:导航到项目目录

cd react-netcore-crud-app

步骤 3:安装 Axios 和 Bootstrap

安装 Axios 以消费后端 API,安装 Bootstrap 用于设计。

npm install axios
npm install bootstrap

步骤 4:添加组件和服务

产品列表组件

// src/components/ProductList/ProductList.js
import React, { useState, useEffect } from 'react';
import ProductListItem from './ProductListItem';
import productService from '../../services/productService';

const ProductList = () => {
    const [products, setProducts] = useState([]);

    useEffect(() => {
        fetchProducts();
    }, []);

    const fetchProducts = async () => {
        try {
            const productsData = await productService.getAllProducts();
            setProducts(productsData);
        } catch (error) {
            console.error('Error fetching products:', error);
        }
    };

    const handleDelete = async (id) => {
        try {
            await productService.deleteProduct(id);
            fetchProducts(); // 刷新产品列表
        } catch (error) {
            console.error('Error deleting product:', error);
        }
    };

    const handleEdit = () => {
        fetchProducts(); // 刷新产品列表以反映编辑
    };

    return (
        <div className="container">
            <h2 className="my-4">Product List</h2>
            <ul className="list-group">
                {Array.isArray(products) && products.length > 0 ? (
                    products.map(product => (
                        <ProductListItem key={product.id} product={product} onDelete={() => handleDelete(product.id)} onEdit={handleEdit} />
                    ))
                ) : (
                    <p>No products available</p>
                )}
            </ul>
        </div>

    );
};

export default ProductList;

产品列表项组件

// src/components/ProductList/Product

ListItem.js
import React from 'react';

const ProductListItem = ({ product, onDelete, onEdit }) => {
    return (
        <li className="list-group-item d-flex justify-content-between align-items-center">
            <div>
                <strong>{product.name}</strong> - ${product.price.toFixed(2)}
            </div>
            <div>
                <button className="btn btn-danger btn-sm" onClick={onDelete}>Delete</button>
                <button className="btn btn-warning btn-sm ms-2" onClick={onEdit}>Edit</button>
            </div>
        </li>

    );
};

export default ProductListItem;

步骤 5:创建服务以消费 API

在 src/services 目录中创建 productService.js 文件。

// src/services/productService.js
import axios from 'axios';

const apiUrl = 'https://localhost:5001/api/products'// 替换为您的后端 API URL

const getAllProducts = async () => {
    const response = await axios.get(apiUrl);
    return response.data;
};

const addProduct = async (product) => {
    await axios.post(apiUrl, product);
};

const deleteProduct = async (id) => {
    await axios.delete(`${apiUrl}/${id}`);
};

const productService = {
    getAllProducts,
    addProduct,
    deleteProduct
};

export default productService;

步骤 6:更新主组件

在 src/App.js 中导入和使用 ProductList 组件。

import React from 'react';
import ProductList from './components/ProductList/ProductList';

const App = () => {
    return (
        <div className="App">
            <header className="App-header">
                <h1>Product Management</h1>
            </header>
            <ProductList />
        </div>

    );
};

export default App;

步骤 7:启动 React 应用

使用以下命令启动 React 应用。

npm start

CRUD 操作

六. 应用程序的 Docker 文件

为 .NET Core Web API 和 React JS 创建 Docker 文件。

.NET Core Dockerfile

# 使用 .NET SDK 镜像构建应用程序
FROM mcr.microsoft.com/dotnet/sdk:6.0 AS build
WORKDIR /app
COPY *.sln .
COPY *.csproj .
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o out

# 使用 ASP.NET Core 运行时镜像部署应用程序
FROM mcr.microsoft.com/dotnet/aspnet:6.0
WORKDIR /app
COPY --from=build /app/out .
ENTRYPOINT ["dotnet""ProductManagementAPI.dll"]

React Dockerfile

# 使用 Node.js 镜像构建 React 应用程序
FROM node:16 AS build
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build

# 使用 Nginx 运行 React 应用程序
FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx""-g""daemon off;"]

七. 容器化应用程序

使用 Docker Compose 管理应用程序的容器。

docker-compose.yml

version: '3.4'

services:
  webapi:
    image: productmanagementapi
    build:
      context: .
      dockerfile: ProductManagementAPI/Dockerfile
    ports:
      - "5000:80"
      
  reactapp:
    image: reactproductapp
    build:
      context: .
      dockerfile: react-netcore-crud-app/Dockerfile
    ports:
      - "3000:80"

步骤 1:构建和运行 Docker 容器

在项目根目录下运行以下命令。

docker-compose up --build

步骤 2:访问应用程序

  • .NET Core Web API:访问 http://localhost:5000/api/products
  • React 应用:访问 http://localhost:3000

八. 使用 Kubernetes 部署

为应用程序创建 Kubernetes 部署和服务。

k8s-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: product-management
spec:
  replicas: 1
  selector:
    matchLabels:
      app: product-management
  template:
    metadata:
      labels:
        app: product-management
    spec:
      containers:
        - name: webapi
          image: productmanagementapi
          ports:
            - containerPort: 80
        - name: reactapp
          image: reactproductapp
          ports:
            - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: product-management-service
spec:
  type: NodePort
  ports:
    - port: 80
      targetPort: 80
  selector:
    app: product-management

步骤 1:应用 Kubernetes 配置

在 Kubernetes 集群中应用配置。

kubectl apply -f k8s-deployment.yaml

步骤 2:访问 Kubernetes 服务

使用以下命令获取服务的外部 IP 和端口。

kubectl get svc

九. 结论

通过本教程,我们创建了一个使用 .NET Core Web API 和 React JS 的简单产品管理应用程序,并使用 Docker 和 Kubernetes 进行了容器化和部署。这为构建可扩展和高效的 Web 应用程序奠定了基础。

您可以根据需要添加更多功能,如身份验证、授权等,以增强应用程序的安全性和功能性。

希望这个完整的示例能帮助您在项目中应用 .NET Core Web API 和 React JS 的知识,并有效利用 Docker 和 Kubernetes。