增加Dockerfile

增加Dockerfile-h3
优化代码
This commit is contained in:
token
2024-04-03 02:01:11 +08:00
parent 56edb3f211
commit e1de06612d
15 changed files with 421 additions and 83 deletions
+3 -1
View File
@@ -27,4 +27,6 @@ README.md
!.git/HEAD
!.git/config
!.git/packed-refs
!.git/refs/heads/**
!.git/refs/heads/**
**/node_modules
**/dist
+7
View File
@@ -0,0 +1,7 @@
docker build -f ./src/FastGateway/Dockerfile -t registry.cn-shenzhen.aliyuncs.com/tokengo/gateway-api:v1.0.0 .
docker push registry.cn-shenzhen.aliyuncs.com/tokengo/gateway-api:v1.0.0
docker build -f ./src/FastGateway/Dockerfile-h3 -t registry.cn-shenzhen.aliyuncs.com/tokengo/gateway-api:v1.0.0-h3 .
docker push registry.cn-shenzhen.aliyuncs.com/tokengo/gateway-api:v1.0.0-h3
+35
View File
@@ -0,0 +1,35 @@
#See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/aspnet:8.0.3-alpine3.18-amd64 AS base
USER app
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
FROM node:alpine as builder
WORKDIR /src
COPY web .
RUN yarn config set strict-ssl false
RUN yarn
RUN yarn build
FROM mcr.microsoft.com/dotnet/sdk:8.0.203-alpine3.18-amd64 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["src/FastGateway/FastGateway.csproj", "src/FastGateway/"]
COPY ["src/FastGateway.Core/FastGateway.Core.csproj", "src/FastGateway.Core/"]
RUN dotnet restore "./src/FastGateway/FastGateway.csproj"
COPY . .
WORKDIR "/src/src/FastGateway"
RUN dotnet build "./FastGateway.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./FastGateway.csproj" -c $BUILD_CONFIGURATION -o /app/publish --os linux /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
COPY --from=builder /src/dist ./wwwroot
ENTRYPOINT ["dotnet", "FastGateway.dll"]
+41
View File
@@ -0,0 +1,41 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0.1-bookworm-slim-amd64 AS base
USER root
RUN apt update \
&& apt-get install -y --no-install-recommends curl \
&& curl -sSL -O https://packages.microsoft.com/config/debian/12/packages-microsoft-prod.deb \
&& dpkg -i packages-microsoft-prod.deb \
&& rm packages-microsoft-prod.deb \
&& apt-get update \
&& apt-get install -y libmsquic \
&& apt-get purge -y --auto-remove wget && apt-get clean && rm -rf /var/lib/apt/lists/*
WORKDIR /app
EXPOSE 8080
EXPOSE 8081
FROM node:alpine as builder
WORKDIR /src
COPY web .
RUN yarn config set strict-ssl false
RUN yarn
RUN yarn build
FROM mcr.microsoft.com/dotnet/sdk:8.0.203-alpine3.18-amd64 AS build
ARG BUILD_CONFIGURATION=Release
WORKDIR /src
COPY ["src/FastGateway/FastGateway.csproj", "src/FastGateway/"]
COPY ["src/FastGateway.Core/FastGateway.Core.csproj", "src/FastGateway.Core/"]
RUN dotnet restore "./src/FastGateway/FastGateway.csproj"
COPY . .
WORKDIR "/src/src/FastGateway"
RUN dotnet build "./FastGateway.csproj" -c $BUILD_CONFIGURATION -o /app/build
FROM build AS publish
ARG BUILD_CONFIGURATION=Release
RUN dotnet publish "./FastGateway.csproj" -c $BUILD_CONFIGURATION -o /app/publish --os linux /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
COPY --from=builder /src/dist ./wwwroot
ENTRYPOINT ["dotnet", "FastGateway.dll"]
+36 -31
View File
@@ -1,37 +1,42 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<ServerGarbageCollection>true</ServerGarbageCollection>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<ServerGarbageCollection>true</ServerGarbageCollection>
<InvariantGlobalization>true</InvariantGlobalization>
<UserSecretsId>3e871fe1-899b-49f4-96c0-4799dd36c406</UserSecretsId>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<DockerfileContext>..\..</DockerfileContext>
<ItemGroup>
<PackageReference Include="Certes" Version="3.0.4" />
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.2-pre01" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.1" />
<PackageReference Include="Yarp.ReverseProxy" Version="2.1.0" />
</ItemGroup>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\FastGateway.Core\FastGateway.Core.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Certes" Version="3.0.4" />
<PackageReference Include="Mapster.DependencyInjection" Version="1.0.2-pre01" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.3">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="8.0.3" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.1" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.20.0" />
<PackageReference Include="Yarp.ReverseProxy" Version="2.1.0" />
</ItemGroup>
<ItemGroup>
<None Update="gateway.pfx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\FastGateway.Core\FastGateway.Core.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="gateway.pfx">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -0,0 +1,239 @@
// <auto-generated />
using System;
using FastGateway.EFCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
#nullable disable
namespace FastGateway.Migrations
{
[DbContext(typeof(MasterDbContext))]
partial class MasterDbContextModelSnapshot : ModelSnapshot
{
protected override void BuildModel(ModelBuilder modelBuilder)
{
#pragma warning disable 612, 618
modelBuilder.HasAnnotation("ProductVersion", "8.0.3");
modelBuilder.Entity("FastGateway.Domain.Cert", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<bool>("AutoRenew")
.HasColumnType("INTEGER");
b.Property<string>("Certs")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Domains")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("Email")
.IsRequired()
.HasColumnType("TEXT");
b.Property<bool>("Expired")
.HasColumnType("INTEGER");
b.Property<string>("Issuer")
.IsRequired()
.HasColumnType("TEXT");
b.Property<DateTime?>("NotAfter")
.HasColumnType("TEXT");
b.Property<int>("RenewStats")
.HasColumnType("INTEGER");
b.Property<DateTime?>("RenewTime")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("cert", (string)null);
});
modelBuilder.Entity("FastGateway.Domain.Location", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<string>("AddHeader")
.IsRequired()
.HasColumnType("TEXT");
b.Property<int>("LoadType")
.HasColumnType("INTEGER");
b.Property<string>("Path")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("ProxyPass")
.HasColumnType("TEXT");
b.Property<string>("Root")
.HasColumnType("TEXT");
b.Property<string>("ServiceId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("TryFiles")
.HasColumnType("TEXT");
b.Property<int>("Type")
.HasColumnType("INTEGER");
b.Property<string>("UpStreams")
.IsRequired()
.HasColumnType("TEXT");
b.HasKey("Id");
b.HasIndex("ServiceId");
b.ToTable("location", (string)null);
});
modelBuilder.Entity("FastGateway.Domain.Service", b =>
{
b.Property<string>("Id")
.HasColumnType("TEXT");
b.Property<bool>("Enable")
.HasColumnType("INTEGER");
b.Property<bool>("EnableFlowMonitoring")
.HasColumnType("INTEGER");
b.Property<bool>("EnableHttp3")
.HasColumnType("INTEGER");
b.Property<bool>("EnableRequestSource")
.HasColumnType("INTEGER");
b.Property<bool>("EnableTunnel")
.HasColumnType("INTEGER");
b.Property<bool>("IsHttps")
.HasColumnType("INTEGER");
b.Property<ushort>("Listen")
.HasColumnType("INTEGER");
b.Property<string>("ServiceNames")
.IsRequired()
.HasColumnType("TEXT");
b.Property<string>("SslCertificate")
.HasColumnType("TEXT");
b.Property<string>("SslCertificatePassword")
.HasColumnType("TEXT");
b.HasKey("Id");
b.ToTable("service", (string)null);
});
modelBuilder.Entity("FastGateway.Domain.StatisticIp", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<int>("Count")
.HasColumnType("INTEGER");
b.Property<byte>("Day")
.HasColumnType("INTEGER");
b.Property<string>("Ip")
.HasColumnType("TEXT");
b.Property<string>("Location")
.HasColumnType("TEXT");
b.Property<byte>("Month")
.HasColumnType("INTEGER");
b.Property<string>("ServiceId")
.HasColumnType("TEXT");
b.Property<ushort>("Year")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.ToTable("statistic_ip", (string)null);
});
modelBuilder.Entity("FastGateway.Domain.StatisticRequestCount", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("INTEGER");
b.Property<byte>("Day")
.HasColumnType("INTEGER");
b.Property<int>("Error4xxCount")
.HasColumnType("INTEGER");
b.Property<int>("Error5xxCount")
.HasColumnType("INTEGER");
b.Property<byte>("Month")
.HasColumnType("INTEGER");
b.Property<int>("RequestCount")
.HasColumnType("INTEGER");
b.Property<string>("ServiceId")
.IsRequired()
.HasColumnType("TEXT");
b.Property<ushort>("Year")
.HasColumnType("INTEGER");
b.HasKey("Id");
b.HasIndex("ServiceId");
b.ToTable("statistic_request_count", (string)null);
});
modelBuilder.Entity("FastGateway.Domain.Location", b =>
{
b.HasOne("FastGateway.Domain.Service", null)
.WithMany("Locations")
.HasForeignKey("ServiceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
});
modelBuilder.Entity("FastGateway.Domain.StatisticRequestCount", b =>
{
b.HasOne("FastGateway.Domain.Service", "Service")
.WithMany()
.HasForeignKey("ServiceId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired();
b.Navigation("Service");
});
modelBuilder.Entity("FastGateway.Domain.Service", b =>
{
b.Navigation("Locations");
});
#pragma warning restore 612, 618
}
}
}
+15 -11
View File
@@ -1,6 +1,7 @@
using FastGateway;
using FastGateway.BackgroundServices;
using FastGateway.Options;
using Microsoft.AspNetCore.ResponseCompression;
var builder = WebApplication.CreateBuilder(args);
@@ -25,6 +26,11 @@ builder.Services.AddSingleton<IQpsService, QpsService>();
builder.Services.AddHostedService<RenewSslBackgroundService>();
builder.Services.AddHostedService<StatisticsBackgroundService>();
builder.Services.AddResponseCompression(options =>
{
options.Providers.Add<BrotliCompressionProvider>();
options.Providers.Add<GzipCompressionProvider>();
});
builder.Services.AddMapster();
builder.Services.AddDbContext<MasterDbContext>(options =>
@@ -38,14 +44,13 @@ builder.Services
var app = builder.Build();
app.UseResponseCompression();
app.UseCors("AllowAll");
app.UseAuthentication();
app.UseAuthorization();
app.MapGet("/.well-known/acme-challenge/{token}", AcmeChallenge.Challenge);
app.MapPost("/.well-known/acme-challenge/{token}", AcmeChallenge.Challenge);
#region Authorize
@@ -144,15 +149,14 @@ statisticService.MapGet("/TotalRequestCount",
FastContext.SetQpsService(app.Services.GetRequiredService<IQpsService>());
if (app.Environment.IsDevelopment())
{
using var scope = app.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<MasterDbContext>();
await db.Database.MigrateAsync();
app.UseStaticFiles();
await ApiServiceService.LoadServices(db);
await CertService.LoadCerts(db);
}
using var scope = app.Services.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<MasterDbContext>();
await db.Database.MigrateAsync();
await ApiServiceService.LoadServices(db);
await CertService.LoadCerts(db);
await app.RunAsync();
+27 -19
View File
@@ -1,33 +1,22 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:46246",
"sslPort": 44346
}
},
{
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5283",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"dotnetRunMessages": true,
"applicationUrl": "http://localhost:5283"
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": false,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7115;http://localhost:5283",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"dotnetRunMessages": true,
"applicationUrl": "https://localhost:7115;http://localhost:5283"
},
"IIS Express": {
"commandName": "IISExpress",
@@ -36,6 +25,25 @@
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"Container (Dockerfile)": {
"commandName": "Docker",
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
"ASPNETCORE_HTTPS_PORTS": "8081",
"ASPNETCORE_HTTP_PORTS": "8080"
},
"publishAllPorts": true,
"useSSL": true
}
},
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:46246",
"sslPort": 44346
}
}
}
}
@@ -354,6 +354,9 @@ public class ApiServiceService
app.UseMiddleware<StatisticsMiddleware>();
app.MapGet("/.well-known/acme-challenge/{token}", AcmeChallenge.Challenge);
app.MapPost("/.well-known/acme-challenge/{token}", AcmeChallenge.Challenge);
foreach (var location in service.Locations.Where(x => x.Type == ApiServiceType.StaticProxy))
{
app.Map(location.Path.TrimEnd('/'), app =>
-6
View File
@@ -1,6 +0,0 @@
<Directives>
<Application>
<Assembly Name="FastGateway" Dynamic="Required All">
</Assembly>
</Application>
</Directives>
+2 -2
View File
@@ -8,7 +8,7 @@ interface ICreateCertProps {
}
const { Input, Switch, Select } = Form;
const { Input, Select } = Form;
export default function CreateCertPage({
visible,
@@ -43,7 +43,7 @@ export default function CreateCertPage({
}}
>
{
({ formState, values, formApi }: any) => (
({ values, formApi }: any) => (
<>
<Select
name="type"
+6 -6
View File
@@ -20,7 +20,7 @@ export default function CertPage() {
title: '类型',
dataIndex: 'autoRenew',
key: 'autoRenew',
render: (text: any, record: any) => (
render: (_text: any, record: any) => (
<div>
{record.autoRenew ? '自动续期' : '上传证书'}
</div>
@@ -30,7 +30,7 @@ export default function CertPage() {
title: '域名',
dataIndex: 'domains',
key: 'domains',
render: (text: any, record: any) => (
render: (_text: any, record: any) => (
<div>
{record.domains.join(',')}
</div>
@@ -45,7 +45,7 @@ export default function CertPage() {
title: '证书状态',
dataIndex: 'renewStats',
key: 'renewStats',
render: (text: any, record: Cert) => (
render: (_text: any, record: Cert) => (
<Tag
color='blue'
size='large'
@@ -59,7 +59,7 @@ export default function CertPage() {
title: '最近续期时间',
dataIndex: 'renewTime',
key: 'renewTime',
render: (text: any, record: any) => (
render: (_text: any, record: any) => (
<div>
{record.renewTime}
</div>
@@ -69,7 +69,7 @@ export default function CertPage() {
title: '有效期',
dataIndex: 'notAfter',
key: 'notAfter',
render: (text: any, record: any) => (
render: (_text: any, record: any) => (
<div>
{record.notAfter}
</div>
@@ -78,7 +78,7 @@ export default function CertPage() {
{
title: '操作',
key: 'action',
render: (text: any, record: any) => (
render: (_text: any, record: any) => (
<Dropdown
render={
<Dropdown.Menu>
+1 -1
View File
@@ -1,4 +1,4 @@
import { Divider, Select, Tag } from '@douyinfe/semi-ui'
import { Divider,Tag } from '@douyinfe/semi-ui'
import './index.css'
import { useEffect, useState } from 'react';
import * as echarts from 'echarts';
@@ -1,4 +1,4 @@
import { ArrayField, Button, Col, Collapse, Divider, Form, InputGroup, Modal, Notification, Row } from "@douyinfe/semi-ui";
import { Button, Col, Collapse, Divider, Form, InputGroup, Modal, Notification, Row } from "@douyinfe/semi-ui";
import { LoadType, LocationInput, ServiceInput } from "../../../module";
import { CheckDirecotryExistence, CreateApiService } from "../../../services/ApiServiceService";
@@ -33,7 +33,7 @@ export default function CreateHttpProxy({
labelCol={{ span: 4 }}
onSubmit={(values: ServiceInput) => {
CreateApiService(values)
.then((res:any) => {
.then(() => {
Notification.success({
title: '创建成功',
content: '创建成功',
@@ -51,7 +51,7 @@ export default function CreateHttpProxy({
>
{
({ formState, values, formApi }: IFormValues) => (
({ values, formApi }: IFormValues) => (
<>
<Select
@@ -1,6 +1,6 @@
import { Button, Col, Collapse, Divider, Form, InputGroup, Modal, Notification, Row } from "@douyinfe/semi-ui";
import { LoadType, LocationInput, Service, ServiceInput } from "../../../module";
import { CheckDirecotryExistence, CreateApiService, UpdateApiService } from "../../../services/ApiServiceService";
import { CheckDirecotryExistence, UpdateApiService } from "../../../services/ApiServiceService";
interface IUpdateHttpProxyProps {
visible: boolean;
@@ -36,7 +36,7 @@ export default function UpdateHttpProxy({
initValues={values}
onSubmit={(values: ServiceInput) => {
UpdateApiService(values.id as string, values)
.then((res: any) => {
.then(() => {
Notification.success({
title: '修改成功',
content: '修改成功',
@@ -54,7 +54,7 @@ export default function UpdateHttpProxy({
>
{
({ formState, values, formApi }: IFormValues) => (
({ values, formApi }: IFormValues) => (
<>
<Select