기능 추가
This commit is contained in:
172
app.py
172
app.py
@@ -1,12 +1,14 @@
|
||||
from flask import Flask, render_template, request, send_file, abort
|
||||
from flask import (
|
||||
Flask, render_template, request,
|
||||
send_file, abort, redirect, url_for
|
||||
)
|
||||
import subprocess
|
||||
import uuid
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
from datetime import datetime
|
||||
import zipfile
|
||||
import yaml # ⭐ 추가
|
||||
|
||||
#app = Flask(__name__)
|
||||
app = Flask(__name__, static_folder="static")
|
||||
|
||||
BASE = Path("/work")
|
||||
@@ -17,12 +19,61 @@ def ts():
|
||||
return datetime.now().strftime("%Y-%m-%d-%H-%M-%S")
|
||||
|
||||
|
||||
# ===== backup YAML sanitize =====
|
||||
|
||||
REMOVE_METADATA_FIELDS = {
|
||||
"uid",
|
||||
"resourceVersion",
|
||||
"generation",
|
||||
"creationTimestamp",
|
||||
"managedFields",
|
||||
}
|
||||
|
||||
def sanitize_backup_yaml(path: Path):
|
||||
docs = list(yaml.safe_load_all(path.read_text()))
|
||||
cleaned = []
|
||||
|
||||
for doc in docs:
|
||||
if not isinstance(doc, dict):
|
||||
cleaned.append(doc)
|
||||
continue
|
||||
|
||||
# metadata 정리
|
||||
meta = doc.get("metadata")
|
||||
if isinstance(meta, dict):
|
||||
for k in list(meta.keys()):
|
||||
if k in REMOVE_METADATA_FIELDS:
|
||||
meta.pop(k, None)
|
||||
|
||||
# status 제거 (rollback 충돌 방지)
|
||||
doc.pop("status", None)
|
||||
|
||||
cleaned.append(doc)
|
||||
|
||||
path.write_text(
|
||||
yaml.safe_dump_all(
|
||||
cleaned,
|
||||
sort_keys=False
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def sanitize_backup_tree(backup_dir: Path):
|
||||
if not backup_dir.exists():
|
||||
return
|
||||
|
||||
for p in backup_dir.rglob("*.yaml"):
|
||||
sanitize_backup_yaml(p)
|
||||
|
||||
|
||||
# ===== routes =====
|
||||
|
||||
@app.route("/", methods=["GET", "POST"])
|
||||
def index():
|
||||
if request.method == "POST":
|
||||
job_id = str(uuid.uuid4())
|
||||
job_dir = BASE / job_id
|
||||
job_dir.mkdir(parents=True)
|
||||
job_dir.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
cmd = [
|
||||
"python3",
|
||||
@@ -33,33 +84,41 @@ def index():
|
||||
|
||||
if request.form.get("from_class"):
|
||||
cmd += ["--from-ingress-class", request.form["from_class"]]
|
||||
|
||||
if request.form.get("to_class"):
|
||||
cmd += ["--ingress-class", request.form["to_class"]]
|
||||
|
||||
if request.form.get("namespace"):
|
||||
cmd += ["--namespace", request.form["namespace"]]
|
||||
|
||||
subprocess.check_call(cmd, cwd=job_dir)
|
||||
|
||||
timestamp = ts()
|
||||
# 🔥 backup YAML 정화
|
||||
sanitize_backup_tree(job_dir / "backup")
|
||||
|
||||
# result.zip (yaml + report)
|
||||
timestamp = ts()
|
||||
result_zip = BASE / f"{timestamp}-result.zip"
|
||||
backup_zip = BASE / f"{timestamp}-backup.zip"
|
||||
|
||||
# result zip
|
||||
with zipfile.ZipFile(result_zip, "w", zipfile.ZIP_DEFLATED) as z:
|
||||
for p in (job_dir / "yaml").rglob("*"):
|
||||
z.write(p, p.relative_to(job_dir))
|
||||
if p.is_file():
|
||||
z.write(p, p.relative_to(job_dir))
|
||||
report = job_dir / "migration-report.md"
|
||||
if report.exists():
|
||||
z.write(report, report.relative_to(job_dir))
|
||||
|
||||
# backup.zip
|
||||
backup_zip = BASE / f"{timestamp}-backup.zip"
|
||||
# backup zip
|
||||
with zipfile.ZipFile(backup_zip, "w", zipfile.ZIP_DEFLATED) as z:
|
||||
for p in (job_dir / "backup").rglob("*"):
|
||||
z.write(p, p.relative_to(job_dir))
|
||||
if p.is_file():
|
||||
z.write(p, p.relative_to(job_dir))
|
||||
|
||||
return preview(job_id, result_zip.name, backup_zip.name)
|
||||
return redirect(url_for(
|
||||
"preview",
|
||||
job_id=job_id,
|
||||
result_zip=result_zip.name,
|
||||
backup_zip=backup_zip.name
|
||||
))
|
||||
|
||||
return render_template("index.html")
|
||||
|
||||
@@ -68,13 +127,14 @@ def index():
|
||||
def preview(job_id, result_zip, backup_zip):
|
||||
job_dir = BASE / job_id
|
||||
|
||||
def tree(root: Path):
|
||||
def tree(root):
|
||||
t = {}
|
||||
if not root.exists():
|
||||
return t
|
||||
for ns in sorted(root.iterdir()):
|
||||
if ns.is_dir():
|
||||
t[ns.name] = sorted(f.name for f in ns.iterdir() if f.is_file())
|
||||
if root.exists():
|
||||
for ns in root.iterdir():
|
||||
if ns.is_dir():
|
||||
t[ns.name] = sorted(
|
||||
f.name for f in ns.iterdir() if f.is_file()
|
||||
)
|
||||
return t
|
||||
|
||||
return render_template(
|
||||
@@ -87,14 +147,35 @@ def preview(job_id, result_zip, backup_zip):
|
||||
)
|
||||
|
||||
|
||||
@app.route("/view/<job_id>/<kind>/<path:path>")
|
||||
@app.route("/view/<job_id>/<kind>/<path:path>", methods=["GET", "POST"])
|
||||
def view_file(job_id, kind, path):
|
||||
if kind not in ("yaml", "backup"):
|
||||
abort(404)
|
||||
|
||||
f = BASE / job_id / kind / path
|
||||
if not f.exists():
|
||||
if not f.exists() or not f.is_file():
|
||||
abort(404)
|
||||
return f"<pre>{f.read_text()}</pre>"
|
||||
|
||||
editable = (kind == "yaml")
|
||||
|
||||
if request.method == "POST":
|
||||
if not editable:
|
||||
abort(403)
|
||||
|
||||
f.write_text(request.form.get("content", ""))
|
||||
return redirect(url_for(
|
||||
"view_file",
|
||||
job_id=job_id,
|
||||
kind=kind,
|
||||
path=path
|
||||
))
|
||||
|
||||
return render_template(
|
||||
"view.html",
|
||||
title=f"{kind.upper()} / {path}",
|
||||
content=f.read_text(),
|
||||
editable=editable
|
||||
)
|
||||
|
||||
|
||||
@app.route("/report/<job_id>")
|
||||
@@ -102,7 +183,52 @@ def view_report(job_id):
|
||||
report = BASE / job_id / "migration-report.md"
|
||||
if not report.exists():
|
||||
abort(404)
|
||||
return f"<pre>{report.read_text()}</pre>"
|
||||
|
||||
return render_template(
|
||||
"view.html",
|
||||
title="Migration Report",
|
||||
content=report.read_text()
|
||||
)
|
||||
|
||||
|
||||
@app.route("/apply/<job_id>/<kind>", methods=["POST"])
|
||||
def apply_yaml(job_id, kind):
|
||||
if kind not in ("yaml", "backup"):
|
||||
abort(400)
|
||||
|
||||
target_dir = BASE / job_id / kind
|
||||
if not target_dir.exists():
|
||||
abort(404)
|
||||
|
||||
if kind == "yaml":
|
||||
cmd = ["kubectl", "replace", "-f", str(target_dir), "--recursive"]
|
||||
title = "Apply Converted YAML"
|
||||
else:
|
||||
cmd = ["kubectl", "replace", "-f", str(target_dir), "--recursive"]
|
||||
title = "Rollback from Backup"
|
||||
|
||||
proc = subprocess.run(
|
||||
cmd,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
text=True
|
||||
)
|
||||
|
||||
output = ""
|
||||
if proc.stdout:
|
||||
output += proc.stdout
|
||||
if proc.stderr:
|
||||
output += "\n" + proc.stderr
|
||||
|
||||
status = "SUCCESS" if proc.returncode == 0 else "FAILED"
|
||||
|
||||
return render_template(
|
||||
"apply_result.html",
|
||||
title=title,
|
||||
status=status,
|
||||
command=" ".join(cmd),
|
||||
output=output
|
||||
)
|
||||
|
||||
|
||||
@app.route("/download/<name>")
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
flask
|
||||
ruamel.yaml
|
||||
gunicorn
|
||||
PyYAML
|
||||
|
||||
135
static/style.css
135
static/style.css
@@ -1,12 +1,24 @@
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
margin: 0;
|
||||
background: #0f172a;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif;
|
||||
background: #020617;
|
||||
color: #e5e7eb;
|
||||
}
|
||||
|
||||
body::before {
|
||||
content: "";
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
background: linear-gradient(180deg, #0b1220, #020617);
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
.container {
|
||||
max-width: 1100px;
|
||||
max-width: 1400px;
|
||||
margin: 40px auto;
|
||||
padding: 24px;
|
||||
}
|
||||
@@ -14,43 +26,85 @@ body {
|
||||
.card {
|
||||
background: #020617;
|
||||
border: 1px solid #1e293b;
|
||||
border-radius: 10px;
|
||||
padding: 20px;
|
||||
border-radius: 14px;
|
||||
padding: 24px;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
margin-top: 0;
|
||||
h1 {
|
||||
margin: 0 0 24px;
|
||||
font-size: 36px;
|
||||
}
|
||||
|
||||
/* ======= FORM LAYOUT (GRID / NO OVERLAP) ======= */
|
||||
|
||||
.form-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr auto;
|
||||
gap: 20px;
|
||||
align-items: end;
|
||||
}
|
||||
|
||||
.field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 14px;
|
||||
color: #94a3b8;
|
||||
margin-bottom: 6px;
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
margin: 6px 0 14px;
|
||||
border-radius: 6px;
|
||||
height: 44px;
|
||||
padding: 10px 12px;
|
||||
font-size: 15px;
|
||||
border-radius: 8px;
|
||||
border: 1px solid #334155;
|
||||
background: #020617;
|
||||
color: #e5e7eb;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
outline: none;
|
||||
border-color: #3b82f6;
|
||||
}
|
||||
|
||||
button {
|
||||
background: #2563eb;
|
||||
color: white;
|
||||
height: 44px;
|
||||
padding: 0 26px;
|
||||
border-radius: 10px;
|
||||
border: none;
|
||||
padding: 10px 18px;
|
||||
border-radius: 6px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
background: #2563eb;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
button:hover {
|
||||
background: #1d4ed8;
|
||||
}
|
||||
|
||||
/* ======= VIEW / PREVIEW ======= */
|
||||
|
||||
pre {
|
||||
background: transparent; /* ❌ 배경 제거 */
|
||||
border: none; /* ❌ 테두리 제거 */
|
||||
padding: 0; /* ❌ 중복 패딩 제거 */
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
overflow-x: auto;
|
||||
color: #e5e7eb;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #60a5fa;
|
||||
text-decoration: none;
|
||||
@@ -60,14 +114,49 @@ a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 18px;
|
||||
.actions-row {
|
||||
display: flex;
|
||||
gap: 14px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
pre {
|
||||
background: #020617;
|
||||
border: 1px solid #1e293b;
|
||||
border-radius: 8px;
|
||||
padding: 16px;
|
||||
overflow-x: auto;
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: 44px;
|
||||
padding: 0 26px;
|
||||
border-radius: 10px;
|
||||
font-size: 15px;
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
background: #2563eb;
|
||||
color: #fff;
|
||||
white-space: nowrap;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
background: #1d4ed8;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.btn-danger {
|
||||
background: #dc2626;
|
||||
}
|
||||
.btn-danger:hover {
|
||||
background: #b91c1c;
|
||||
}
|
||||
|
||||
.editor {
|
||||
width: 100%;
|
||||
min-height: 600px;
|
||||
background: transparent;
|
||||
color: #e5e7eb;
|
||||
border: none;
|
||||
outline: none;
|
||||
resize: vertical;
|
||||
font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
28
templates/apply_result.html
Normal file
28
templates/apply_result.html
Normal file
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ title }}</title>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>{{ title }}</h1>
|
||||
|
||||
<div class="card">
|
||||
<p><strong>Status:</strong> {{ status }}</p>
|
||||
<p><strong>Command:</strong></p>
|
||||
<pre>{{ command }}</pre>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>kubectl output</h3>
|
||||
<pre>{{ output }}</pre>
|
||||
</div>
|
||||
|
||||
<div class="card actions-row">
|
||||
<button onclick="history.back()">Back</button>
|
||||
<a class="btn" href="/">Home</a>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -9,15 +9,21 @@
|
||||
<h1>Ingress Migrator</h1>
|
||||
|
||||
<div class="card">
|
||||
<form method="post">
|
||||
<label>From ingressClass</label>
|
||||
<input name="from_class" value="nginx">
|
||||
<form method="post" class="form-grid">
|
||||
<div class="field">
|
||||
<label>From ingressClass</label>
|
||||
<input name="from_class" value="nginx">
|
||||
</div>
|
||||
|
||||
<label>To ingressClass</label>
|
||||
<input name="to_class" value="haproxy">
|
||||
<div class="field">
|
||||
<label>To ingressClass</label>
|
||||
<input name="to_class" value="haproxy">
|
||||
</div>
|
||||
|
||||
<label>Namespace (optional)</label>
|
||||
<input name="namespace">
|
||||
<div class="field">
|
||||
<label>Namespace (optional)</label>
|
||||
<input name="namespace">
|
||||
</div>
|
||||
|
||||
<button type="submit">Run Migration</button>
|
||||
</form>
|
||||
|
||||
@@ -1,44 +1,61 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Result</title>
|
||||
<title>Ingress Migrator - Preview</title>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
|
||||
<h1>Migration Result</h1>
|
||||
<h1>Migration Preview</h1>
|
||||
|
||||
<div class="card">
|
||||
<h2>Converted YAML</h2>
|
||||
{% for ns, files in yaml_tree.items() %}
|
||||
<h4>{{ ns }}</h4>
|
||||
<ul>
|
||||
{% for f in files %}
|
||||
<li><a href="/view/{{ job_id }}/yaml/{{ ns }}/{{ f }}">{{ f }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
<h3>Converted YAML</h3>
|
||||
<ul>
|
||||
{% for ns, files in yaml_tree.items() %}
|
||||
<li><strong>{{ ns }}</strong>
|
||||
<ul>
|
||||
{% for f in files %}
|
||||
<li>
|
||||
<a href="/view/{{ job_id }}/yaml/{{ ns }}/{{ f }}">{{ f }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h2>Original Backup</h2>
|
||||
{% for ns, files in backup_tree.items() %}
|
||||
<h4>{{ ns }}</h4>
|
||||
<ul>
|
||||
{% for f in files %}
|
||||
<li><a href="/view/{{ job_id }}/backup/{{ ns }}/{{ f }}">{{ f }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endfor %}
|
||||
<h3>Original Backup</h3>
|
||||
<ul>
|
||||
{% for ns, files in backup_tree.items() %}
|
||||
<li><strong>{{ ns }}</strong>
|
||||
<ul>
|
||||
{% for f in files %}
|
||||
<li>
|
||||
<a href="/view/{{ job_id }}/backup/{{ ns }}/{{ f }}">{{ f }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<a href="/report/{{ job_id }}">📄 migration-report.md</a><br><br>
|
||||
<a href="/download/{{ result_zip }}">⬇ result.zip</a><br>
|
||||
<a href="/download/{{ backup_zip }}">⬇ backup.zip</a>
|
||||
<div class="card actions-row">
|
||||
<a class="btn" href="/report/{{ job_id }}">View Migration Report</a>
|
||||
<a class="btn" href="/download/{{ result_zip }}">Download Result ZIP</a>
|
||||
<a class="btn" href="/download/{{ backup_zip }}">Download Backup ZIP</a>
|
||||
</div>
|
||||
<div class="card actions-row">
|
||||
<form method="post" action="/apply/{{ job_id }}/yaml">
|
||||
<button class="btn btn-danger" type="submit">Replace Converted YAML</button>
|
||||
</form>
|
||||
<form method="post" action="/apply/{{ job_id }}/backup">
|
||||
<button class="btn" type="submit">Rollback from Backup</button>
|
||||
</form>
|
||||
<button onclick="history.back()">Back</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,2 +1,20 @@
|
||||
<h2>Migration Report</h2>
|
||||
<pre>{{ content }}</pre>
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Migration Report</title>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>Migration Report</h1>
|
||||
|
||||
<div class="card">
|
||||
<pre>{{ content }}</pre>
|
||||
</div>
|
||||
|
||||
<div class="card actions-row">
|
||||
<button class="btn" onclick="history.back()">Back</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
33
templates/view.html
Normal file
33
templates/view.html
Normal file
@@ -0,0 +1,33 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>{{ title }}</title>
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h2>{{ title }}</h2>
|
||||
|
||||
<div class="card">
|
||||
{% if editable %}
|
||||
<form method="post">
|
||||
<textarea name="content" class="editor">{{ content }}</textarea>
|
||||
|
||||
<div class="actions-row" style="margin-top:16px;">
|
||||
<button type="submit">Save</button>
|
||||
<button type="button" onclick="history.back()">Cancel</button>
|
||||
</div>
|
||||
</form>
|
||||
{% else %}
|
||||
<pre>{{ content }}</pre>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
{% if not editable %}
|
||||
<div class="card actions-row">
|
||||
<button onclick="history.back()">Back</button>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
26
yaml/account.yaml
Normal file
26
yaml/account.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: ingress-migrator
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: ingress-migrator
|
||||
rules:
|
||||
- apiGroups: ["networking.k8s.io"]
|
||||
resources: ["ingresses"]
|
||||
verbs: ["get", "list", "update", "patch"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: ingress-migrator
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: ingress-migrator
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: ingress-migrator
|
||||
namespace: testapp
|
||||
57
yaml/configmap.yaml
Normal file
57
yaml/configmap.yaml
Normal file
@@ -0,0 +1,57 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: ingress-migrator-mapping
|
||||
data:
|
||||
mapping.yaml: |
|
||||
nginx.ingress.kubernetes.io/affinity:
|
||||
haproxy: haproxy.org/cookie-persistence
|
||||
support: partial
|
||||
note: "value 수정 필요 (ex. cookie -> route)"
|
||||
|
||||
nginx.ingress.kubernetes.io/backend-protocol:
|
||||
haproxy: haproxy.org/server-ssl
|
||||
support: partial
|
||||
note: "value 수정 필요 (ex. HTTPS -> true)"
|
||||
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect:
|
||||
haproxy: haproxy.org/ssl-redirect
|
||||
support: full
|
||||
|
||||
nginx.ingress.kubernetes.io/session-cookie-hash:
|
||||
haproxy: null
|
||||
support: unsupported
|
||||
note: "HAProxy는 해시 방식 지정 불필요 (자동 제공)"
|
||||
|
||||
nginx.ingress.kubernetes.io/session-cookie-name:
|
||||
haproxy: haproxy.org/cookie-persistence
|
||||
support: full
|
||||
|
||||
nginx.ingress.kubernetes.io/ssl-redirect:
|
||||
haproxy: haproxy.org/ssl-redirect
|
||||
support: full
|
||||
|
||||
nginx.ingress.kubernetes.io/server-snippet:
|
||||
haproxy: haproxy.org/backend-config-snippet
|
||||
support: partial
|
||||
note: "value 수정 필요"
|
||||
|
||||
nginx.ingress.kubernetes.io/app-root:
|
||||
haproxy: haproxy.org/path-rewrite
|
||||
support: partial
|
||||
note: "Change Value"
|
||||
|
||||
nginx.ingress.kubernetes.io/configuration-snippet:
|
||||
haproxy: null
|
||||
support: unsupported
|
||||
note: "HAProxy does not support arbitrary NGINX snippets"
|
||||
|
||||
proxy-buffering:
|
||||
haproxy: null
|
||||
support: unsupported
|
||||
note: "HAProxy does not support arbitrary NGINX snippets"
|
||||
|
||||
gzip-level:
|
||||
haproxy: null
|
||||
support: unsupported
|
||||
note: "HAProxy does not support arbitrary NGINX snippets"
|
||||
32
yaml/deploy.yaml
Normal file
32
yaml/deploy.yaml
Normal file
@@ -0,0 +1,32 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: ingress-migrator-web
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: ingress-migrator-web
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: ingress-migrator-web
|
||||
spec:
|
||||
serviceAccountName: ingress-migrator
|
||||
containers:
|
||||
- name: web
|
||||
image: sa8001/ngtoha:v3
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
volumeMounts:
|
||||
- name: work
|
||||
mountPath: /work
|
||||
- name: mapping
|
||||
mountPath: /app/mapping.yaml
|
||||
subPath: mapping.yaml
|
||||
volumes:
|
||||
- name: work
|
||||
emptyDir: {}
|
||||
- name: mapping
|
||||
configMap:
|
||||
name: ingress-migrator-mapping
|
||||
11
yaml/svc.yaml
Normal file
11
yaml/svc.yaml
Normal file
@@ -0,0 +1,11 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: ingress-migrator-web
|
||||
spec:
|
||||
selector:
|
||||
app: ingress-migrator-web
|
||||
ports:
|
||||
- port: 80
|
||||
targetPort: 8080
|
||||
type: NodePort
|
||||
Reference in New Issue
Block a user