docker
This commit is contained in:
9
.dockerignore
Normal file
9
.dockerignore
Normal file
@@ -0,0 +1,9 @@
|
||||
node_modules
|
||||
dist
|
||||
.angular
|
||||
.git
|
||||
.env
|
||||
coverage
|
||||
npm-debug.log*
|
||||
apps/api/dist
|
||||
apps/web/dist
|
||||
@@ -3,6 +3,7 @@ NODE_ENV=development
|
||||
API_PORT=3000
|
||||
WEB_PORT=4200
|
||||
PUBLIC_WEB_URL=http://localhost:4200
|
||||
API_BASE_URL=http://localhost:3000
|
||||
|
||||
DATABASE_URL=mysql://ldap_portal:change-me@mysql.example.com:3306/ldap_portal
|
||||
DATABASE_SSL=false
|
||||
|
||||
34
Dockerfile
Normal file
34
Dockerfile
Normal file
@@ -0,0 +1,34 @@
|
||||
FROM node:22-alpine AS deps
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
COPY apps/api/package.json apps/api/package.json
|
||||
COPY apps/web/package.json apps/web/package.json
|
||||
RUN npm ci
|
||||
|
||||
FROM deps AS build
|
||||
COPY tsconfig.base.json ./
|
||||
COPY eslint.config.mjs ./
|
||||
COPY apps/api apps/api
|
||||
COPY apps/web apps/web
|
||||
RUN npm run build
|
||||
|
||||
FROM node:22-alpine AS runtime
|
||||
WORKDIR /app
|
||||
ENV NODE_ENV=production
|
||||
ENV API_PORT=3000
|
||||
ENV WEB_PORT=8080
|
||||
ENV API_BASE_URL=http://localhost:3000
|
||||
|
||||
RUN apk add --no-cache nginx
|
||||
|
||||
COPY --from=deps /app/node_modules node_modules
|
||||
COPY --from=build /app/apps/api/dist api
|
||||
COPY --from=build /app/apps/web/dist/web/browser /usr/share/nginx/html
|
||||
COPY apps/api/package.json package.json
|
||||
COPY docker/single-container.nginx.conf /etc/nginx/http.d/default.conf
|
||||
COPY docker/start-single-container.sh /usr/local/bin/start-ldap-portal
|
||||
RUN chmod +x /usr/local/bin/start-ldap-portal \
|
||||
&& mkdir -p /run/nginx /var/log/nginx
|
||||
|
||||
EXPOSE 3000 8080
|
||||
CMD ["start-ldap-portal"]
|
||||
27
README.md
27
README.md
@@ -35,6 +35,33 @@ docker compose up --build
|
||||
Passe vor dem Start mindestens `DATABASE_URL`, `JWT_SECRET`, `TOKEN_SECRET`, `LLDAP_*` und `SMTP_*` an.
|
||||
Fuer OIDC muessen zusaetzlich `OIDC_ISSUER`, `OIDC_COOKIE_SECRET`, `OIDC_ADMIN_GROUP` und `OIDC_ADMIN_GROUP_UUID` gesetzt werden.
|
||||
|
||||
## Single Container Image
|
||||
|
||||
Das Root-`Dockerfile` baut API und Angular in ein einzelnes Image. Der Container startet:
|
||||
|
||||
- NestJS API / IdP auf Port `3000`
|
||||
- Nginx Web-UI auf Port `8080`
|
||||
|
||||
Build und Push:
|
||||
|
||||
```bash
|
||||
docker build -t registry.example.com/ldap-portal/idp:latest .
|
||||
docker push registry.example.com/ldap-portal/idp:latest
|
||||
```
|
||||
|
||||
Start:
|
||||
|
||||
```bash
|
||||
docker run -d --name ldap-portal-idp \
|
||||
--env-file .env \
|
||||
-e API_BASE_URL=https://id.example.com \
|
||||
-p 3000:3000 \
|
||||
-p 8080:8080 \
|
||||
registry.example.com/ldap-portal/idp:latest
|
||||
```
|
||||
|
||||
`API_BASE_URL` wird beim Containerstart in `/config.js` geschrieben und vom Angular-Frontend gelesen. Setze es auf die aus Browser-Sicht erreichbare API-/IdP-URL.
|
||||
|
||||
## Externe Dienste
|
||||
|
||||
Die Anwendung bringt keine Datenbank und keinen LLDAP-Server mehr per Compose mit. Erwartet werden:
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
"browser": "src/main.ts",
|
||||
"polyfills": ["zone.js"],
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"assets": ["src/favicon.ico"],
|
||||
"assets": ["src/favicon.ico", "src/config.js"],
|
||||
"styles": ["src/styles.css"]
|
||||
},
|
||||
"configurations": {
|
||||
|
||||
3
apps/web/src/config.js
Normal file
3
apps/web/src/config.js
Normal file
@@ -0,0 +1,3 @@
|
||||
window.__LDAP_PORTAL_CONFIG__ = {
|
||||
apiBaseUrl: 'http://localhost:3000'
|
||||
};
|
||||
@@ -5,6 +5,7 @@
|
||||
<title>LDAP Portal</title>
|
||||
<base href="/">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script src="/config.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
|
||||
@@ -19,6 +19,14 @@ import { VerifyEmailComponent } from './app/pages/verify-email.component';
|
||||
import { API_BASE_URL } from './app/shared/api-base-url';
|
||||
import { AuthService } from './app/shared/auth.service';
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__LDAP_PORTAL_CONFIG__?: {
|
||||
apiBaseUrl?: string;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const authInterceptor: HttpInterceptorFn = (request, next) => {
|
||||
const token = localStorage.getItem('accessToken');
|
||||
if (!token) {
|
||||
@@ -58,6 +66,6 @@ bootstrapApplication(AppComponent, {
|
||||
provideRouter(routes),
|
||||
provideHttpClient(withInterceptors([authInterceptor])),
|
||||
AuthService,
|
||||
{ provide: API_BASE_URL, useValue: 'http://localhost:3000' },
|
||||
{ provide: API_BASE_URL, useValue: window.__LDAP_PORTAL_CONFIG__?.apiBaseUrl ?? 'http://localhost:3000' },
|
||||
],
|
||||
}).catch((error) => console.error(error));
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
services:
|
||||
api:
|
||||
app:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: apps/api/Dockerfile
|
||||
dockerfile: Dockerfile
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- "3000:3000"
|
||||
|
||||
web:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: apps/web/Dockerfile
|
||||
environment:
|
||||
API_BASE_URL: http://localhost:3000
|
||||
ports:
|
||||
- "4200:80"
|
||||
depends_on:
|
||||
- api
|
||||
- "3000:3000"
|
||||
- "8080:8080"
|
||||
|
||||
15
docker/single-container.nginx.conf
Normal file
15
docker/single-container.nginx.conf
Normal file
@@ -0,0 +1,15 @@
|
||||
server {
|
||||
listen 8080;
|
||||
server_name _;
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
location = /config.js {
|
||||
add_header Cache-Control "no-store";
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
}
|
||||
24
docker/start-single-container.sh
Normal file
24
docker/start-single-container.sh
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
cat >/usr/share/nginx/html/config.js <<EOF
|
||||
window.__LDAP_PORTAL_CONFIG__ = {
|
||||
apiBaseUrl: "${API_BASE_URL:-http://localhost:3000}"
|
||||
};
|
||||
EOF
|
||||
|
||||
node /app/api/main.js &
|
||||
api_pid="$!"
|
||||
|
||||
nginx -g "daemon off;" &
|
||||
nginx_pid="$!"
|
||||
|
||||
term() {
|
||||
kill "$api_pid" "$nginx_pid" 2>/dev/null || true
|
||||
wait "$api_pid" "$nginx_pid" 2>/dev/null || true
|
||||
}
|
||||
|
||||
trap term INT TERM
|
||||
|
||||
wait -n "$api_pid" "$nginx_pid"
|
||||
term
|
||||
Reference in New Issue
Block a user