add: поддержка докера

This commit is contained in:
mfnefd 2024-12-09 04:16:30 +04:00
parent a9c20be67a
commit 1996e69e80
16 changed files with 372 additions and 12 deletions

25
.dockerignore Normal file
View File

@ -0,0 +1,25 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/bin
**/charts
**/docker-compose*
**/compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md

5
.env Normal file
View File

@ -0,0 +1,5 @@
POSTGRES_DB="dombudg"
POSTGRES_USER="postgres"
POSTGRES_PASSWORD="postgres"
CONNECTION_STRING="Host=database:5432;Database=${POSTGRES_DB};Username=${POSTGRES_USER};Password=${POSTGRES_PASSWORD};"

39
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,39 @@
{
"version": "0.2.0",
"configurations": [
{
"name": ".NET Core Launch (web)",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "${workspaceFolder}/back/Controllers/bin/Debug/net8.0/Controllers.dll",
"args": [],
"cwd": "${workspaceFolder}/back/Controllers",
"stopAtEntry": false,
"serverReadyAction": {
"action": "openExternally",
"pattern": "\\bNow listening on:\\s+(https?://\\S+)"
},
"env": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"sourceFileMap": {
"/Views": "${workspaceFolder}/Views"
}
},
{
"name": ".NET Core Attach",
"type": "coreclr",
"request": "attach"
},
{
"name": "Docker .NET Launch",
"type": "docker",
"request": "launch",
"preLaunchTask": "docker-run: debug",
"netCore": {
"appProject": "${workspaceFolder}/back/Controllers/Controllers.csproj"
}
}
]
}

101
.vscode/tasks.json vendored Normal file
View File

@ -0,0 +1,101 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "build",
"command": "dotnet",
"type": "process",
"args": [
"build",
"${workspaceFolder}/back/Api.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "publish",
"command": "dotnet",
"type": "process",
"args": [
"publish",
"${workspaceFolder}/back/Api.sln",
"/property:GenerateFullPaths=true",
"/consoleloggerparameters:NoSummary;ForceNoAlign"
],
"problemMatcher": "$msCompile"
},
{
"label": "watch",
"command": "dotnet",
"type": "process",
"args": [
"watch",
"run",
"--project",
"${workspaceFolder}/back/Api.sln"
],
"problemMatcher": "$msCompile"
},
{
"type": "docker-build",
"label": "docker-build: debug",
"dependsOn": [
"build"
],
"dockerBuild": {
"tag": "dombudg:dev",
"target": "base",
"dockerfile": "${workspaceFolder}/back/Controllers/Dockerfile",
"context": "${workspaceFolder}",
"pull": true
},
"netCore": {
"appProject": "${workspaceFolder}/back/Controllers/Controllers.csproj"
}
},
{
"type": "docker-build",
"label": "docker-build: release",
"dependsOn": [
"build"
],
"dockerBuild": {
"tag": "dombudg:latest",
"dockerfile": "${workspaceFolder}/back/Controllers/Dockerfile",
"context": "${workspaceFolder}",
"platform": {
"os": "linux",
"architecture": "amd64"
},
"pull": true
},
"netCore": {
"appProject": "${workspaceFolder}/back/Controllers/Controllers.csproj"
}
},
{
"type": "docker-run",
"label": "docker-run: debug",
"dependsOn": [
"docker-build: debug"
],
"dockerRun": {},
"netCore": {
"appProject": "${workspaceFolder}/back/Controllers/Controllers.csproj",
"enableDebugging": true
}
},
{
"type": "docker-run",
"label": "docker-run: release",
"dependsOn": [
"docker-build: release"
],
"dockerRun": {},
"netCore": {
"appProject": "${workspaceFolder}/back/Controllers/Controllers.csproj"
}
}
]
}

View File

@ -0,0 +1,24 @@
FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base
WORKDIR /app
EXPOSE 5125
ENV ASPNETCORE_URLS=http://+:5125
USER app
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 AS build
ARG configuration=Release
WORKDIR /src
COPY ["back/Controllers/Controllers.csproj", "back/Controllers/"]
RUN dotnet restore "back/Controllers/Controllers.csproj"
COPY . .
WORKDIR "/src/back/Controllers"
RUN dotnet build "Controllers.csproj" -c $configuration -o /app/build
FROM build AS publish
ARG configuration=Release
RUN dotnet publish "Controllers.csproj" -c $configuration -o /app/publish /p:UseAppHost=false
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Controllers.dll"]

View File

@ -9,6 +9,7 @@ public static class DatabaseSetupExtension
{
var connectionString = config.GetConnectionString("DefaultConnection")
?? throw new ArgumentException("Нет строки подключения");
Console.WriteLine("Connection string: " + connectionString);
services.AddDbContext<DatabaseContext>(options => options.UseNpgsql(connectionString));
services.AddSingleton<IDbContextFactory<DatabaseContext>, DbContextFactory>();
}

41
docker-compose.debug.yml Normal file
View File

@ -0,0 +1,41 @@
# Please refer https://aka.ms/HTTPSinContainer on how to setup an https developer certificate for your ASP.NET Core service.
services:
api:
image: api
build:
context: .
dockerfile: back/Controllers/Dockerfile
args:
- configuration=Debug
ports:
- 5125:5125
environment:
- ConnectionStrings__DefaultConnection=${CONNECTION_STRING}
- ASPNETCORE_ENVIRONMENT=Development
volumes:
- ~/.vsdbg:/remote_debugger:rw
depends_on:
- database
dombudg:
image: dombudg
build:
context: front
dockerfile: ./Dockerfile
environment:
- VITE_API_URL=http://api:5125
ports:
- 80:80
depends_on:
- api
database:
image: postgres:14
environment:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
driver: local

35
docker-compose.yml Normal file
View File

@ -0,0 +1,35 @@
services:
api:
image: api
build:
context: .
dockerfile: back/Controllers/Dockerfile
ports:
- 5125:5125
environment:
- ConnectionStrings__DefaultConnection=${CONNECTION_STRING}
depends_on:
- database
dombudg:
image: dombudg
build:
context: front
dockerfile: ./Dockerfile
environment:
- VITE_API_URL=http://api:5125
ports:
- 80:80
depends_on:
- api
database:
image: postgres:14
environment:
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
driver: local

24
front/.dockerignore Normal file
View File

@ -0,0 +1,24 @@
**/.classpath
**/.dockerignore
**/.env
**/.git
**/.gitignore
**/.project
**/.settings
**/.toolstarget
**/.vs
**/.vscode
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/charts
**/docker-compose*
**/compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
**/obj
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md

18
front/Dockerfile Normal file
View File

@ -0,0 +1,18 @@
FROM node as vite-app
ARG VITE_API_URL
WORKDIR /app/client
COPY . .
RUN ["npm", "i"]
RUN ["npm", "run", "build"]
FROM nginx:alpine
COPY nginx.conf /etc/nginx
RUN rm -rf /usr/share/nginx/html/*
COPY --from=vite-app /app/client/dist /usr/share/nginx/html
ENTRYPOINT ["nginx", "-g", "daemon off;"]

View File

@ -8,9 +8,7 @@ export {}
declare module 'vue' {
export interface GlobalComponents {
AButton: typeof import('ant-design-vue/es')['Button']
ACol: typeof import('ant-design-vue/es')['Col']
ADatePicker: typeof import('ant-design-vue/es')['DatePicker']
AFlex: typeof import('ant-design-vue/es')['Flex']
AForm: typeof import('ant-design-vue/es')['Form']
AFormItem: typeof import('ant-design-vue/es')['FormItem']
AInput: typeof import('ant-design-vue/es')['Input']
@ -19,23 +17,17 @@ declare module 'vue' {
ALayout: typeof import('ant-design-vue/es')['Layout']
ALayoutContent: typeof import('ant-design-vue/es')['LayoutContent']
ALayoutHeader: typeof import('ant-design-vue/es')['LayoutHeader']
AMenu: typeof import('ant-design-vue/es')['Menu']
AMenuItem: typeof import('ant-design-vue/es')['MenuItem']
APopconfirm: typeof import('ant-design-vue/es')['Popconfirm']
ARow: typeof import('ant-design-vue/es')['Row']
ASelect: typeof import('ant-design-vue/es')['Select']
ASelectOption: typeof import('ant-design-vue/es')['SelectOption']
ASpace: typeof import('ant-design-vue/es')['Space']
ASpin: typeof import('ant-design-vue/es')['Spin']
ATable: typeof import('ant-design-vue/es')['Table']
ATypographyText: typeof import('ant-design-vue/es')['TypographyText']
ChangeRecordManager: typeof import('./src/components/support/ChangeRecordManager.vue')['default']
ChangeRecordMenu: typeof import('./src/components/support/ChangeRecordMenu.vue')['default']
Groups: typeof import('./src/components/pages/Groups.vue')['default']
Header: typeof import('./src/components/main/Header.vue')['default']
Home: typeof import('./src/components/pages/Home.vue')['default']
Login: typeof import('./src/components/pages/Login.vue')['default']
Manager: typeof import('./src/components/support/Manager.vue')['default']
PlanManager: typeof import('./src/components/support/PlanManager.vue')['default']
Plans: typeof import('./src/components/pages/Plans.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']

55
front/nginx.conf Normal file
View File

@ -0,0 +1,55 @@
# Запускать в качестве менее привилегированного пользователя по соображениям безопасности..
user nginx;
# Значение auto устанавливает число максимально доступных ядер CPU,
# чтобы обеспечить лучшую производительность.
worker_processes auto;
events { worker_connections 1024; }
http {
server {
# Hide nginx version information.
server_tokens off;
listen 80;
root /usr/share/nginx/html;
include /etc/nginx/mime.types;
location /api/ {
proxy_pass http://api:5125/api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Prefix /test;
}
location / {
try_files $uri $uri/ /index.html;
}
gzip on;
gzip_vary on;
gzip_http_version 1.0;
gzip_comp_level 5;
gzip_types
application/atom+xml
application/javascript
application/json
application/rss+xml
application/vnd.ms-fontobject
application/x-font-ttf
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/opentype
image/svg+xml
image/x-icon
text/css
text/plain
text/x-component;
gzip_proxied no-cache no-store private expired auth;
gzip_min_length 256;
gunzip on;
}
}

View File

@ -60,7 +60,7 @@ const formState = reactive<UserDto>({
password: '',
balance: 0
});
const authService = inject(typeof(AuthService)) as AuthService;
const authService = inject(AuthService.name) as AuthService;
// Логика формы
const onFinish = async (values: any) => {

View File

@ -49,7 +49,7 @@
</template>
<script setup lang="ts">
import { computed, inject, reactive, ref } from 'vue';
import { ChangeRecordDto, SpendingGroupViewModel } from '../../core/api/data-contracts';
import { ChangeRecordDto } from '../../core/api/data-contracts';
import { useUserStore } from '../../store';
import { ChangeRecordService } from '../../core/services/change-record-service';
import { GroupService } from '../../core/services/group-service';

View File

@ -55,7 +55,7 @@ export enum ContentType {
}
export class HttpClient<SecurityDataType = unknown> {
public baseUrl: string = "http://localhost:5125";
public baseUrl: string = import.meta.env.VITE_API_URL;
private securityData: SecurityDataType | null = null;
private securityWorker?: ApiConfig<SecurityDataType>["securityWorker"];
private abortControllers = new Map<CancelToken, AbortController>();

View File

@ -34,7 +34,7 @@ const router = createRouter({
],
});
router.beforeEach((to, from, next) => {
router.beforeEach((to, _, next) => {
const store = useUserStore();
if (!to.meta.notRequiresAuth && !store.user.id) {
next({ name: 'login' });