From 20ca50c12727f6a8e927d5dde992033aaa76e8a7 Mon Sep 17 00:00:00 2001 From: zetaloop Date: Tue, 5 May 2026 12:08:10 +0800 Subject: [PATCH] feat(deploy): add k01 business cluster manifests for k3s with cnpg, strimzi, redis and mongodb operators --- deploy/k01/.env.example | 24 + deploy/k01/.gitignore | 2 + deploy/k01/00-base/namespace.yaml | 38 + deploy/k01/01-infra/envoy.yaml | 1096 +++++++++++++++++ deploy/k01/01-infra/kafka.yaml | 72 ++ deploy/k01/01-infra/load-schema.sh | 58 + deploy/k01/01-infra/mongo.yaml | 41 + deploy/k01/01-infra/postgres.yaml | 185 +++ deploy/k01/01-infra/ratelimit.yaml | 149 +++ deploy/k01/01-infra/redis.yaml | 346 ++++++ deploy/k01/02-service/authz-adapter.yaml | 48 + deploy/k01/02-service/chat.yaml | 97 ++ deploy/k01/02-service/community.yaml | 136 ++ deploy/k01/02-service/dispute.yaml | 138 +++ deploy/k01/02-service/email.yaml | 143 +++ deploy/k01/02-service/frontend.yaml | 43 + deploy/k01/02-service/game.yaml | 134 ++ deploy/k01/02-service/notification.yaml | 134 ++ deploy/k01/02-service/objectstory.yaml | 127 ++ deploy/k01/02-service/order.yaml | 138 +++ deploy/k01/02-service/player.yaml | 136 ++ deploy/k01/02-service/review.yaml | 138 +++ deploy/k01/02-service/search.yaml | 134 ++ deploy/k01/02-service/shop.yaml | 138 +++ deploy/k01/02-service/snowflake.yaml | 43 + deploy/k01/02-service/user-verifications.yaml | 83 ++ deploy/k01/02-service/user.yaml | 156 +++ deploy/k01/02-service/wallet.yaml | 134 ++ deploy/k01/README.md | 118 ++ deploy/k01/install-k3s.sh | 78 ++ deploy/k01/secrets.sh | 89 ++ 31 files changed, 4396 insertions(+) create mode 100644 deploy/k01/.env.example create mode 100644 deploy/k01/.gitignore create mode 100644 deploy/k01/00-base/namespace.yaml create mode 100644 deploy/k01/01-infra/envoy.yaml create mode 100644 deploy/k01/01-infra/kafka.yaml create mode 100755 deploy/k01/01-infra/load-schema.sh create mode 100644 deploy/k01/01-infra/mongo.yaml create mode 100644 deploy/k01/01-infra/postgres.yaml create mode 100644 deploy/k01/01-infra/ratelimit.yaml create mode 100644 deploy/k01/01-infra/redis.yaml create mode 100644 deploy/k01/02-service/authz-adapter.yaml create mode 100644 deploy/k01/02-service/chat.yaml create mode 100644 deploy/k01/02-service/community.yaml create mode 100644 deploy/k01/02-service/dispute.yaml create mode 100644 deploy/k01/02-service/email.yaml create mode 100644 deploy/k01/02-service/frontend.yaml create mode 100644 deploy/k01/02-service/game.yaml create mode 100644 deploy/k01/02-service/notification.yaml create mode 100644 deploy/k01/02-service/objectstory.yaml create mode 100644 deploy/k01/02-service/order.yaml create mode 100644 deploy/k01/02-service/player.yaml create mode 100644 deploy/k01/02-service/review.yaml create mode 100644 deploy/k01/02-service/search.yaml create mode 100644 deploy/k01/02-service/shop.yaml create mode 100644 deploy/k01/02-service/snowflake.yaml create mode 100644 deploy/k01/02-service/user-verifications.yaml create mode 100644 deploy/k01/02-service/user.yaml create mode 100644 deploy/k01/02-service/wallet.yaml create mode 100644 deploy/k01/README.md create mode 100755 deploy/k01/install-k3s.sh create mode 100755 deploy/k01/secrets.sh diff --git a/deploy/k01/.env.example b/deploy/k01/.env.example new file mode 100644 index 0000000..7a53e70 --- /dev/null +++ b/deploy/k01/.env.example @@ -0,0 +1,24 @@ +REGISTRY_HOST=registry.juwan.xhttp.zip +REGISTRY_USERNAME=admin +REGISTRY_PASSWORD= + +JWT_SECRET_KEY= +ADMIN_USERNAME=admin +ADMIN_PASSWORD= +ADMIN_EMAIL=admin@juwan.xhttp.zip + +EMAIL_SMTP_HOST=smtp-relay.brevo.com +EMAIL_SMTP_PORT=587 +EMAIL_SMTP_USERNAME= +EMAIL_SMTP_PASSWORD= +EMAIL_FROM_ADDRESS=dev@juwan.xhttp.zip +EMAIL_FROM_NAME=Juwan Team +EMAIL_REPLY_TO= + +S3_ENDPOINT=https://s3.juwan.xhttp.zip +S3_ACCESS_KEY= +S3_SECRET_KEY= +S3_BUCKET_NAME=juwan-objectstory +S3_REGION=garage + +MONGO_PASSWORD= diff --git a/deploy/k01/.gitignore b/deploy/k01/.gitignore new file mode 100644 index 0000000..c3cb00e --- /dev/null +++ b/deploy/k01/.gitignore @@ -0,0 +1,2 @@ +secrets/ +.env diff --git a/deploy/k01/00-base/namespace.yaml b/deploy/k01/00-base/namespace.yaml new file mode 100644 index 0000000..5485458 --- /dev/null +++ b/deploy/k01/00-base/namespace.yaml @@ -0,0 +1,38 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: juwan + +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + namespace: juwan + name: find-endpoints + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: discov-endpoints +rules: + - apiGroups: [""] + resources: ["endpoints"] + verbs: ["get", "list", "watch"] + - apiGroups: ["discovery.k8s.io"] + resources: ["endpointslices"] + verbs: ["get", "list", "watch"] + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: find-endpoints-discov-endpoints +subjects: + - kind: ServiceAccount + namespace: juwan + name: find-endpoints +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: discov-endpoints diff --git a/deploy/k01/01-infra/envoy.yaml b/deploy/k01/01-infra/envoy.yaml new file mode 100644 index 0000000..4c5f597 --- /dev/null +++ b/deploy/k01/01-infra/envoy.yaml @@ -0,0 +1,1096 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: envoy-gateway + namespace: juwan + +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: envoy-config + namespace: juwan +data: + envoy.yaml: | + static_resources: + listeners: + - name: ingress_http + address: + socket_address: + address: "::" + port_value: 8080 + ipv4_compat: true + filter_chains: + - filters: + - name: envoy.filters.network.http_connection_manager + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager + stat_prefix: ingress_http + codec_type: AUTO + generate_request_id: true + use_remote_address: true + xff_num_trusted_hops: 1 + route_config: + name: local_route + virtual_hosts: + - name: juwan_services + domains: ["*"] + routes: + - match: + path: /healthz + direct_response: + status: 200 + body: + inline_string: ok + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + path: /api/v1/auth/login + route: + cluster: user_api_cluster + timeout: 30s + rate_limits: + - actions: + - generic_key: + descriptor_value: login + - remote_address: {} + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + path: /api/v1/auth/register + route: + cluster: user_api_cluster + timeout: 30s + rate_limits: + - actions: + - generic_key: + descriptor_value: register + - remote_address: {} + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + path: /api/v1/auth/reset-password + route: + cluster: user_api_cluster + timeout: 30s + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + path: /api/v1/auth/forgot-password/send + route: + cluster: email_api_cluster + timeout: 30s + rate_limits: + - actions: + - generic_key: + descriptor_value: forgot_password_send + - remote_address: {} + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + path: /api/v1/email/verification-code/send + route: + cluster: email_api_cluster + timeout: 30s + rate_limits: + - actions: + - generic_key: + descriptor_value: verify_code_send + - remote_address: {} + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + prefix: /api/v1/games + headers: + - name: ":method" + exact_match: GET + route: + cluster: game_api_cluster + timeout: 30s + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + path: /api/v1/players/me + headers: + - name: ":method" + exact_match: GET + route: + cluster: player_api_cluster + timeout: 30s + + - match: + prefix: /api/v1/players + headers: + - name: ":method" + exact_match: GET + route: + cluster: player_api_cluster + timeout: 30s + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + prefix: /api/v1/services + headers: + - name: ":method" + exact_match: GET + route: + cluster: player_api_cluster + timeout: 30s + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + path: /api/v1/shops + headers: + - name: ":method" + exact_match: GET + route: + cluster: shop_api_cluster + timeout: 30s + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + safe_regex: + google_re2: {} + regex: "^/api/v1/shops/[0-9]+$" + headers: + - name: ":method" + exact_match: GET + route: + cluster: shop_api_cluster + timeout: 30s + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + safe_regex: + google_re2: {} + regex: "^/api/v1/users/[0-9]+$" + headers: + - name: ":method" + exact_match: GET + route: + cluster: user_api_cluster + timeout: 30s + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + safe_regex: + google_re2: {} + regex: "^/api/v1/users/[0-9]+/posts$" + headers: + - name: ":method" + exact_match: GET + route: + cluster: community_api_cluster + timeout: 30s + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + safe_regex: + google_re2: {} + regex: "^/api/v1/users/[0-9]+/shop$" + headers: + - name: ":method" + exact_match: GET + route: + cluster: shop_api_cluster + timeout: 30s + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + path: /api/v1/search + headers: + - name: ":method" + exact_match: GET + route: + cluster: search_api_cluster + timeout: 30s + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + prefix: /api/v1/recommendations + headers: + - name: ":method" + exact_match: GET + route: + cluster: search_api_cluster + timeout: 30s + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + prefix: /api/v1/posts + headers: + - name: ":method" + exact_match: GET + route: + cluster: community_api_cluster + timeout: 30s + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + prefix: /api/v1/auth + route: + cluster: user_api_cluster + timeout: 30s + + - match: + prefix: /api/v1/admin + route: + cluster: user_api_cluster + timeout: 30s + + - match: + safe_regex: + google_re2: {} + regex: "^/api/v1/users/[0-9]+/favorites/check$" + route: + cluster: search_api_cluster + timeout: 30s + + - match: + safe_regex: + google_re2: {} + regex: "^/api/v1/users/[0-9]+/reviews$" + headers: + - name: ":method" + exact_match: GET + route: + cluster: review_api_cluster + timeout: 30s + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + prefix: /api/v1/users + route: + cluster: user_api_cluster + timeout: 30s + + - match: + prefix: /api/v1/email + route: + cluster: email_api_cluster + timeout: 30s + + - match: + prefix: /api/v1/games + route: + cluster: game_api_cluster + timeout: 30s + + - match: + prefix: /api/v1/players + route: + cluster: player_api_cluster + timeout: 30s + + - match: + prefix: /api/v1/services + route: + cluster: player_api_cluster + timeout: 30s + + - match: + prefix: /api/v1/shops + route: + cluster: shop_api_cluster + timeout: 30s + + - match: + safe_regex: + google_re2: {} + regex: "^/api/v1/orders/[0-9]+/review.*" + route: + cluster: review_api_cluster + timeout: 30s + + - match: + safe_regex: + google_re2: {} + regex: "^/api/v1/orders/[0-9]+/dispute$" + route: + cluster: dispute_api_cluster + timeout: 30s + + - match: + prefix: /api/v1/orders + route: + cluster: order_api_cluster + timeout: 30s + + - match: + prefix: /api/v1/wallet + route: + cluster: wallet_api_cluster + timeout: 30s + + - match: + prefix: /api/v1/posts + route: + cluster: community_api_cluster + timeout: 30s + + - match: + prefix: /api/v1/comments + route: + cluster: community_api_cluster + timeout: 30s + + - match: + path: /ws/chat + route: + cluster: chat_api_cluster + timeout: 0s + upgrade_configs: + - upgrade_type: websocket + + - match: + path: /api/v1/upload + route: + cluster: objectstory_api_cluster + timeout: 30s + + - match: + prefix: /api/v1/files + route: + cluster: objectstory_api_cluster + timeout: 30s + + - match: + prefix: /api/v1/reviews + headers: + - name: ":method" + exact_match: GET + route: + cluster: review_api_cluster + timeout: 30s + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + - match: + prefix: /api/v1/disputes + route: + cluster: dispute_api_cluster + timeout: 30s + + - match: + prefix: /api/v1/notifications + route: + cluster: notification_api_cluster + timeout: 30s + + - match: + prefix: /api/v1/favorites + route: + cluster: search_api_cluster + timeout: 30s + + - match: + prefix: / + route: + cluster: frontend_cluster + timeout: 30s + typed_per_filter_config: + envoy.filters.http.ext_authz: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute + disabled: true + + access_log: + - name: envoy.access_loggers.stdout + typed_config: + "@type": type.googleapis.com/envoy.extensions.access_loggers.stream.v3.StdoutAccessLog + log_format: + json_format: + start_time: "%START_TIME%" + method: "%REQ(:METHOD)%" + path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%" + protocol: "%PROTOCOL%" + authority: "%REQ(:AUTHORITY)%" + user_agent: "%REQ(USER-AGENT)%" + request_id: "%REQ(X-REQUEST-ID)%" + response_code: "%RESPONSE_CODE%" + response_flags: "%RESPONSE_FLAGS%" + bytes_received: "%BYTES_RECEIVED%" + bytes_sent: "%BYTES_SENT%" + duration_ms: "%DURATION%" + upstream_cluster: "%UPSTREAM_CLUSTER%" + upstream_host: "%UPSTREAM_HOST%" + upstream_service_time_ms: "%RESP(X-ENVOY-UPSTREAM-SERVICE-TIME)%" + route_name: "%ROUTE_NAME%" + + http_filters: + - name: envoy.filters.http.lua + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.lua.v3.Lua + inline_code: | + local TOKEN_HEADER = "xsrf-token" + local TOKEN_COOKIE = "__Host-XSRF-TOKEN" + local GUARD_COOKIE = "__Host-XSRF-GUARD" + + local seeded = false + + local function seed_random() + if seeded then + return + end + seeded = true + math.randomseed(os.time()) + end + + local function split_cookie(header) + local out = {} + if not header then + return out + end + for pair in string.gmatch(header, "([^;]+)") do + local key, value = string.match(pair, "^%s*([^=]+)=?(.*)$") + if key ~= nil and value ~= nil then + out[string.lower(key)] = value + end + end + return out + end + + local function is_safe_method(method) + return method == "GET" or method == "HEAD" or method == "OPTIONS" + end + + local function build_token(request_id) + seed_random() + local rnd = tostring(math.random(100000, 999999)) + local rid = request_id or "rid" + return tostring(os.time()) .. "-" .. rid .. "-" .. rnd + end + + function envoy_on_request(request_handle) + local headers = request_handle:headers() + local method = headers:get(":method") + + local cookie_header = headers:get("cookie") + local cookies = split_cookie(cookie_header) + local token_cookie = cookies[string.lower(TOKEN_COOKIE)] + local guard_cookie = cookies[string.lower(GUARD_COOKIE)] + + request_handle:streamInfo():dynamicMetadata():set("csrf", "need_set_token_cookie", token_cookie == nil or token_cookie == "") + request_handle:streamInfo():dynamicMetadata():set("csrf", "need_set_guard_cookie", guard_cookie == nil or guard_cookie == "") + + if token_cookie == nil or token_cookie == "" then + token_cookie = build_token(headers:get("x-request-id")) + request_handle:streamInfo():dynamicMetadata():set("csrf", "token_value", token_cookie) + else + request_handle:streamInfo():dynamicMetadata():set("csrf", "token_value", token_cookie) + end + + if guard_cookie == nil or guard_cookie == "" then + guard_cookie = build_token(headers:get("x-request-id")) + request_handle:streamInfo():dynamicMetadata():set("csrf", "guard_value", guard_cookie) + else + request_handle:streamInfo():dynamicMetadata():set("csrf", "guard_value", guard_cookie) + end + + if is_safe_method(method) then + return + end + + local token_header = headers:get(TOKEN_HEADER) + + if token_header == nil or token_header == "" then + request_handle:respond( + {[":status"] = "403", ["content-type"] = "application/json"}, + '{"code":403,"message":"missing XSRF-TOKEN header"}' + ) + return + end + + if token_cookie == nil or token_cookie == "" or guard_cookie == nil or guard_cookie == "" then + request_handle:respond( + {[":status"] = "403", ["content-type"] = "application/json"}, + '{"code":403,"message":"missing csrf cookies"}' + ) + return + end + + if token_header ~= token_cookie then + request_handle:respond( + {[":status"] = "403", ["content-type"] = "application/json"}, + '{"code":403,"message":"xsrf token mismatch"}' + ) + return + end + end + + function envoy_on_response(response_handle) + local metadata = response_handle:streamInfo():dynamicMetadata():get("csrf") + if metadata == nil then + return + end + + local token_value = metadata["token_value"] + local guard_value = metadata["guard_value"] + + if metadata["need_set_token_cookie"] == true and token_value ~= nil and token_value ~= "" then + response_handle:headers():add( + "set-cookie", + TOKEN_COOKIE .. "=" .. token_value .. "; Path=/; Max-Age=7200; SameSite=Strict; Secure" + ) + end + + if metadata["need_set_guard_cookie"] == true and guard_value ~= nil and guard_value ~= "" then + response_handle:headers():add( + "set-cookie", + GUARD_COOKIE .. "=" .. guard_value .. "; Path=/; Max-Age=7200; SameSite=Strict; Secure; HttpOnly" + ) + end + end + + - name: envoy.filters.http.jwt_authn + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.jwt_authn.v3.JwtAuthentication + providers: + juwan_user_jwt: + issuer: juwan-user-rpc + from_cookies: + - JToken + local_jwks: + inline_string: '{"keys":[{"kty":"oct","k":"TUdVeU1XRTNaRGhqTVRRNVpEZzFNV1ZpT1dVME1HTTNPVEUyTldWa1lUQmxPVEU1WldSa1pEVTFZall6T0dKak9XUmlOek0wTlRjNE5ESXlNamxrWlE","alg":"HS256","use":"sig","kid":"juwan-hs256-1"}]}' + forward: false + claim_to_headers: + - header_name: x-auth-user-id + claim_name: UserId + - header_name: x-auth-is-admin + claim_name: IsAdmin + rules: + - match: + path: /healthz + - match: + path: /ws/chat + requires: + provider_name: juwan_user_jwt + - match: + prefix: /api/v1 + headers: + - name: ":method" + exact_match: OPTIONS + - match: + path: /api/v1/auth/login + - match: + path: /api/v1/auth/register + - match: + path: /api/v1/auth/forgot-password + - match: + path: /api/v1/auth/reset-password + - match: + path: /api/v1/auth/forgot-password/send + - match: + path: /api/v1/email/verification-code/send + - match: + prefix: /api/v1/games + headers: + - name: ":method" + exact_match: GET + - match: + path: /api/v1/players/me + headers: + - name: ":method" + exact_match: GET + requires: + provider_name: juwan_user_jwt + - match: + prefix: /api/v1/players + headers: + - name: ":method" + exact_match: GET + - match: + prefix: /api/v1/services + headers: + - name: ":method" + exact_match: GET + - match: + path: /api/v1/shops + headers: + - name: ":method" + exact_match: GET + - match: + safe_regex: + google_re2: {} + regex: "^/api/v1/shops/[0-9]+$" + headers: + - name: ":method" + exact_match: GET + - match: + safe_regex: + google_re2: {} + regex: "^/api/v1/users/[0-9]+$" + headers: + - name: ":method" + exact_match: GET + - match: + safe_regex: + google_re2: {} + regex: "^/api/v1/users/[0-9]+/posts$" + headers: + - name: ":method" + exact_match: GET + requires: + requires_any: + requirements: + - provider_name: juwan_user_jwt + - allow_missing: {} + - match: + safe_regex: + google_re2: {} + regex: "^/api/v1/users/[0-9]+/shop$" + headers: + - name: ":method" + exact_match: GET + - match: + prefix: /api/v1/posts + headers: + - name: ":method" + exact_match: GET + requires: + requires_any: + requirements: + - provider_name: juwan_user_jwt + - allow_missing: {} + - match: + prefix: /api/v1/reviews + headers: + - name: ":method" + exact_match: GET + - match: + safe_regex: + google_re2: {} + regex: "^/api/v1/users/[0-9]+/reviews$" + headers: + - name: ":method" + exact_match: GET + - match: + path: /api/v1/search + headers: + - name: ":method" + exact_match: GET + - match: + path: /api/v1/recommendations/home + headers: + - name: ":method" + exact_match: GET + - match: + prefix: /api/v1 + requires: + provider_name: juwan_user_jwt + + - name: envoy.filters.http.ext_authz + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz + transport_api_version: V3 + failure_mode_allow: false + with_request_body: + max_request_bytes: 8192 + allow_partial_message: true + grpc_service: + envoy_grpc: + cluster_name: authz_adapter_cluster + timeout: 0.5s + + - name: envoy.filters.http.ratelimit + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.ratelimit.v3.RateLimit + domain: api + failure_mode_deny: false + rate_limited_as_resource_exhausted: true + enable_x_ratelimit_headers: DRAFT_VERSION_03 + rate_limit_service: + transport_api_version: V3 + grpc_service: + envoy_grpc: + cluster_name: ratelimit_cluster + timeout: 0.2s + + - name: envoy.filters.http.router + typed_config: + "@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router + + clusters: + - name: user_api_cluster + connect_timeout: 2s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: user_api_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: user-api-svc.juwan + port_value: 8888 + + - name: email_api_cluster + connect_timeout: 2s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: email_api_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: email-api-svc.juwan + port_value: 8888 + + - name: player_api_cluster + connect_timeout: 2s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: player_api_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: player-api-svc.juwan + port_value: 8888 + + - name: game_api_cluster + connect_timeout: 2s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: game_api_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: game-api-svc.juwan + port_value: 8888 + + - name: shop_api_cluster + connect_timeout: 2s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: shop_api_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: shop-api-svc.juwan + port_value: 8888 + + - name: order_api_cluster + connect_timeout: 2s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: order_api_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: order-api-svc.juwan + port_value: 8888 + + - name: wallet_api_cluster + connect_timeout: 2s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: wallet_api_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: wallet-api-svc.juwan + port_value: 8888 + + - name: community_api_cluster + connect_timeout: 2s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: community_api_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: community-api-svc.juwan + port_value: 8888 + + - name: objectstory_api_cluster + connect_timeout: 2s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: objectstory_api_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: objectstory-api-svc.juwan + port_value: 8888 + + - name: chat_api_cluster + connect_timeout: 2s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: chat_api_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: chat-api-svc.juwan + port_value: 8888 + + - name: review_api_cluster + connect_timeout: 2s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: review_api_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: review-api-svc.juwan + port_value: 8888 + + - name: dispute_api_cluster + connect_timeout: 2s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: dispute_api_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: dispute-api-svc.juwan + port_value: 8888 + + - name: notification_api_cluster + connect_timeout: 2s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: notification_api_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: notification-api-svc.juwan + port_value: 8888 + + - name: search_api_cluster + connect_timeout: 2s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: search_api_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: search-api-svc.juwan + port_value: 8888 + + - name: authz_adapter_cluster + connect_timeout: 0.5s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + http2_protocol_options: {} + load_assignment: + cluster_name: authz_adapter_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: authz-adapter-svc.juwan + port_value: 9002 + + - name: ratelimit_cluster + connect_timeout: 0.25s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + http2_protocol_options: {} + load_assignment: + cluster_name: ratelimit_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: ratelimit-svc.juwan + port_value: 8081 + + - name: frontend_cluster + connect_timeout: 2s + type: STRICT_DNS + lb_policy: ROUND_ROBIN + load_assignment: + cluster_name: frontend_cluster + endpoints: + - lb_endpoints: + - endpoint: + address: + socket_address: + address: frontend-svc.juwan + port_value: 3000 + + admin: + access_log_path: /tmp/admin.log + address: + socket_address: + address: 0.0.0.0 + port_value: 9901 + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: envoy-gateway + namespace: juwan + labels: + app: envoy-gateway +spec: + replicas: 1 + selector: + matchLabels: + app: envoy-gateway + template: + metadata: + labels: + app: envoy-gateway + spec: + serviceAccountName: envoy-gateway + containers: + - name: envoy + image: envoyproxy/envoy:v1.38.0 + command: + - /usr/local/bin/envoy + - -c + - /etc/envoy/envoy.yaml + - --log-level + - info + - --disable-hot-restart + ports: + - containerPort: 8080 + name: http + - containerPort: 9901 + name: admin + volumeMounts: + - name: config + mountPath: /etc/envoy + readinessProbe: + httpGet: + path: /healthz + port: 8080 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + requests: + cpu: 100m + memory: 128Mi + volumes: + - name: config + configMap: + name: envoy-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: envoy-gateway-svc + namespace: juwan +spec: + type: NodePort + ports: + - name: http + port: 8080 + targetPort: 8080 + nodePort: 30080 + selector: + app: envoy-gateway + +--- +apiVersion: v1 +kind: Service +metadata: + name: envoy-admin-svc + namespace: juwan +spec: + ports: + - name: admin + port: 9901 + targetPort: 9901 + selector: + app: envoy-gateway diff --git a/deploy/k01/01-infra/kafka.yaml b/deploy/k01/01-infra/kafka.yaml new file mode 100644 index 0000000..5c572ac --- /dev/null +++ b/deploy/k01/01-infra/kafka.yaml @@ -0,0 +1,72 @@ +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaNodePool +metadata: + name: controller + namespace: kafka + labels: + strimzi.io/cluster: juwan-kafka +spec: + replicas: 1 + roles: + - controller + storage: + type: persistent-claim + size: 1Gi + deleteClaim: false + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaNodePool +metadata: + name: broker + namespace: kafka + labels: + strimzi.io/cluster: juwan-kafka +spec: + replicas: 1 + roles: + - broker + storage: + type: persistent-claim + size: 5Gi + deleteClaim: false + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: Kafka +metadata: + name: juwan-kafka + namespace: kafka + annotations: + strimzi.io/node-pools: enabled + strimzi.io/kraft: enabled +spec: + kafka: + version: 4.2.0 + metadataVersion: 4.2-IV0 + listeners: + - name: plain + port: 9092 + type: internal + tls: false + config: + offsets.topic.replication.factor: 1 + transaction.state.log.replication.factor: 1 + transaction.state.log.min.isr: 1 + default.replication.factor: 1 + min.insync.replicas: 1 + entityOperator: + topicOperator: {} + userOperator: {} + +--- +apiVersion: kafka.strimzi.io/v1beta2 +kind: KafkaTopic +metadata: + name: email-task + namespace: kafka + labels: + strimzi.io/cluster: juwan-kafka +spec: + partitions: 1 + replicas: 1 diff --git a/deploy/k01/01-infra/load-schema.sh b/deploy/k01/01-infra/load-schema.sh new file mode 100755 index 0000000..2e9defc --- /dev/null +++ b/deploy/k01/01-infra/load-schema.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash +set -euo pipefail + +K01_DIR="$(cd "$(dirname "$0")" && pwd)" +REPO_ROOT="$(cd "$K01_DIR/../.." && pwd)" +SQL_DIR="$REPO_ROOT/desc/sql" +FIXTURE_DIR="$REPO_ROOT/deploy/dev/fixture" + +export KUBECONFIG=/etc/rancher/k3s/k3s.yaml + +declare -A SCHEMA_MAP=( + [user-db]=users + [player-db]=player + [game-db]=game + [shop-db]=shop + [order-db]=order + [wallet-db]=wallet + [community-db]=community + [review-db]=review + [dispute-db]=dispute + [notification-db]=notification + [search-db]=search +) + +psql_exec() { + local cluster="$1" sql="$2" + kubectl -n juwan exec -i "${cluster}-1" -c postgres -- psql \ + -v ON_ERROR_STOP=1 -U app -d app <<<"$sql" +} + +psql_file() { + local cluster="$1" file="$2" + kubectl -n juwan exec -i "${cluster}-1" -c postgres -- psql \ + -v ON_ERROR_STOP=1 -U app -d app < "$file" +} + +for cluster in "${!SCHEMA_MAP[@]}"; do + domain="${SCHEMA_MAP[$cluster]}" + echo ">>> $cluster ($domain)" + + kubectl -n juwan wait --for=condition=Ready "cluster.postgresql.cnpg.io/${cluster}" --timeout=300s + + psql_file "$cluster" "$SQL_DIR/common/update_updated_at_column.sql" + + for f in "$SQL_DIR/$domain"/*.sql; do + [ -f "$f" ] || continue + echo " schema: $(basename "$f")" + psql_file "$cluster" "$f" + done + + if [ -f "$FIXTURE_DIR/$domain.sql" ]; then + echo " fixture: $domain.sql" + psql_file "$cluster" "$FIXTURE_DIR/$domain.sql" + fi +done + +echo +echo "schema + fixture loaded into 11 CNPG clusters" diff --git a/deploy/k01/01-infra/mongo.yaml b/deploy/k01/01-infra/mongo.yaml new file mode 100644 index 0000000..f165012 --- /dev/null +++ b/deploy/k01/01-infra/mongo.yaml @@ -0,0 +1,41 @@ +apiVersion: mongodbcommunity.mongodb.com/v1 +kind: MongoDBCommunity +metadata: + name: chat-mongodb + namespace: juwan +spec: + members: 1 + type: ReplicaSet + version: "8.2.6" + security: + authentication: + modes: + - SCRAM + users: + - name: app-user + db: admin + passwordSecretRef: + name: chat-mongodb-app-user-password + roles: + - name: readWrite + db: juwan_chat + scramCredentialsSecretName: chat-mongodb-app-user-scram + additionalMongodConfig: + storage.wiredTiger.engineConfig.journalCompressor: zlib + statefulSet: + spec: + volumeClaimTemplates: + - metadata: + name: data-volume + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + - metadata: + name: logs-volume + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 256Mi diff --git a/deploy/k01/01-infra/postgres.yaml b/deploy/k01/01-infra/postgres.yaml new file mode 100644 index 0000000..c19d00b --- /dev/null +++ b/deploy/k01/01-infra/postgres.yaml @@ -0,0 +1,185 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + namespace: juwan + name: user-db +spec: + instances: 1 + imageName: ghcr.io/cloudnative-pg/postgresql:18.3-system-trixie + primaryUpdateStrategy: unsupervised + bootstrap: + initdb: + database: app + owner: app + storage: + size: 1Gi + +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + namespace: juwan + name: player-db +spec: + instances: 1 + imageName: ghcr.io/cloudnative-pg/postgresql:18.3-system-trixie + primaryUpdateStrategy: unsupervised + bootstrap: + initdb: + database: app + owner: app + storage: + size: 1Gi + +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + namespace: juwan + name: game-db +spec: + instances: 1 + imageName: ghcr.io/cloudnative-pg/postgresql:18.3-system-trixie + primaryUpdateStrategy: unsupervised + bootstrap: + initdb: + database: app + owner: app + storage: + size: 1Gi + +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + namespace: juwan + name: shop-db +spec: + instances: 1 + imageName: ghcr.io/cloudnative-pg/postgresql:18.3-system-trixie + primaryUpdateStrategy: unsupervised + bootstrap: + initdb: + database: app + owner: app + storage: + size: 1Gi + +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + namespace: juwan + name: order-db +spec: + instances: 1 + imageName: ghcr.io/cloudnative-pg/postgresql:18.3-system-trixie + primaryUpdateStrategy: unsupervised + bootstrap: + initdb: + database: app + owner: app + storage: + size: 1Gi + +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + namespace: juwan + name: wallet-db +spec: + instances: 1 + imageName: ghcr.io/cloudnative-pg/postgresql:18.3-system-trixie + primaryUpdateStrategy: unsupervised + bootstrap: + initdb: + database: app + owner: app + storage: + size: 1Gi + +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + namespace: juwan + name: community-db +spec: + instances: 1 + imageName: ghcr.io/cloudnative-pg/postgresql:18.3-system-trixie + primaryUpdateStrategy: unsupervised + bootstrap: + initdb: + database: app + owner: app + storage: + size: 1Gi + +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + namespace: juwan + name: review-db +spec: + instances: 1 + imageName: ghcr.io/cloudnative-pg/postgresql:18.3-system-trixie + primaryUpdateStrategy: unsupervised + bootstrap: + initdb: + database: app + owner: app + storage: + size: 1Gi + +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + namespace: juwan + name: dispute-db +spec: + instances: 1 + imageName: ghcr.io/cloudnative-pg/postgresql:18.3-system-trixie + primaryUpdateStrategy: unsupervised + bootstrap: + initdb: + database: app + owner: app + storage: + size: 1Gi + +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + namespace: juwan + name: notification-db +spec: + instances: 1 + imageName: ghcr.io/cloudnative-pg/postgresql:18.3-system-trixie + primaryUpdateStrategy: unsupervised + bootstrap: + initdb: + database: app + owner: app + storage: + size: 1Gi + +--- +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + namespace: juwan + name: search-db +spec: + instances: 1 + imageName: ghcr.io/cloudnative-pg/postgresql:18.3-system-trixie + primaryUpdateStrategy: unsupervised + bootstrap: + initdb: + database: app + owner: app + storage: + size: 1Gi diff --git a/deploy/k01/01-infra/ratelimit.yaml b/deploy/k01/01-infra/ratelimit.yaml new file mode 100644 index 0000000..84d5ba3 --- /dev/null +++ b/deploy/k01/01-infra/ratelimit.yaml @@ -0,0 +1,149 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: ratelimit-config + namespace: juwan +data: + ratelimit.yaml: | + domain: api + descriptors: + - key: generic_key + value: login + descriptors: + - key: remote_address + rate_limit: + unit: MINUTE + requests_per_unit: 10 + - key: generic_key + value: register + descriptors: + - key: remote_address + rate_limit: + unit: MINUTE + requests_per_unit: 5 + - key: generic_key + value: forgot_password_send + descriptors: + - key: remote_address + rate_limit: + unit: MINUTE + requests_per_unit: 3 + - key: generic_key + value: verify_code_send + descriptors: + - key: remote_address + rate_limit: + unit: MINUTE + requests_per_unit: 3 + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: rl-redis + namespace: juwan + labels: + app: rl-redis +spec: + replicas: 1 + selector: + matchLabels: + app: rl-redis + template: + metadata: + labels: + app: rl-redis + spec: + containers: + - name: redis + image: redis:8.6.2-alpine + ports: + - containerPort: 6379 + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: rl-redis-svc + namespace: juwan +spec: + ports: + - port: 6379 + targetPort: 6379 + selector: + app: rl-redis + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: ratelimit + namespace: juwan + labels: + app: ratelimit +spec: + replicas: 1 + selector: + matchLabels: + app: ratelimit + template: + metadata: + labels: + app: ratelimit + spec: + containers: + - name: ratelimit + image: envoyproxy/ratelimit:fe26676d + command: ["/bin/ratelimit"] + env: + - name: REDIS_SOCKET_TYPE + value: tcp + - name: REDIS_URL + value: rl-redis-svc:6379 + - name: USE_STATSD + value: "false" + - name: RUNTIME_ROOT + value: /data + - name: RUNTIME_SUBDIRECTORY + value: ratelimit + - name: RUNTIME_WATCH_ROOT + value: "true" + - name: LOG_LEVEL + value: info + ports: + - containerPort: 8081 + name: grpc + - containerPort: 6070 + name: debug + volumeMounts: + - name: config + mountPath: /data/ratelimit/config + resources: + requests: + cpu: 50m + memory: 64Mi + volumes: + - name: config + configMap: + name: ratelimit-config + +--- +apiVersion: v1 +kind: Service +metadata: + name: ratelimit-svc + namespace: juwan +spec: + ports: + - name: grpc + port: 8081 + targetPort: 8081 + - name: debug + port: 6070 + targetPort: 6070 + selector: + app: ratelimit diff --git a/deploy/k01/01-infra/redis.yaml b/deploy/k01/01-infra/redis.yaml new file mode 100644 index 0000000..3392aa9 --- /dev/null +++ b/deploy/k01/01-infra/redis.yaml @@ -0,0 +1,346 @@ +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: user-redis + namespace: juwan +spec: + clusterSize: 1 + kubernetesConfig: + image: quay.io/opstree/redis:v7.0.15 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 64Mi + redisSecret: + name: user-redis + key: password + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + storage: + volumeClaimTemplate: + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + +--- +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: player-redis + namespace: juwan +spec: + clusterSize: 1 + kubernetesConfig: + image: quay.io/opstree/redis:v7.0.15 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 64Mi + redisSecret: + name: player-redis + key: password + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + storage: + volumeClaimTemplate: + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + +--- +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: game-redis + namespace: juwan +spec: + clusterSize: 1 + kubernetesConfig: + image: quay.io/opstree/redis:v7.0.15 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 64Mi + redisSecret: + name: game-redis + key: password + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + storage: + volumeClaimTemplate: + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + +--- +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: shop-redis + namespace: juwan +spec: + clusterSize: 1 + kubernetesConfig: + image: quay.io/opstree/redis:v7.0.15 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 64Mi + redisSecret: + name: shop-redis + key: password + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + storage: + volumeClaimTemplate: + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + +--- +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: order-redis + namespace: juwan +spec: + clusterSize: 1 + kubernetesConfig: + image: quay.io/opstree/redis:v7.0.15 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 64Mi + redisSecret: + name: order-redis + key: password + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + storage: + volumeClaimTemplate: + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + +--- +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: wallet-redis + namespace: juwan +spec: + clusterSize: 1 + kubernetesConfig: + image: quay.io/opstree/redis:v7.0.15 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 64Mi + redisSecret: + name: wallet-redis + key: password + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + storage: + volumeClaimTemplate: + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + +--- +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: community-redis + namespace: juwan +spec: + clusterSize: 1 + kubernetesConfig: + image: quay.io/opstree/redis:v7.0.15 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 64Mi + redisSecret: + name: community-redis + key: password + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + storage: + volumeClaimTemplate: + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + +--- +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: review-redis + namespace: juwan +spec: + clusterSize: 1 + kubernetesConfig: + image: quay.io/opstree/redis:v7.0.15 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 64Mi + redisSecret: + name: review-redis + key: password + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + storage: + volumeClaimTemplate: + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + +--- +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: dispute-redis + namespace: juwan +spec: + clusterSize: 1 + kubernetesConfig: + image: quay.io/opstree/redis:v7.0.15 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 64Mi + redisSecret: + name: dispute-redis + key: password + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + storage: + volumeClaimTemplate: + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + +--- +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: notification-redis + namespace: juwan +spec: + clusterSize: 1 + kubernetesConfig: + image: quay.io/opstree/redis:v7.0.15 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 64Mi + redisSecret: + name: notification-redis + key: password + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + storage: + volumeClaimTemplate: + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + +--- +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: search-redis + namespace: juwan +spec: + clusterSize: 1 + kubernetesConfig: + image: quay.io/opstree/redis:v7.0.15 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 64Mi + redisSecret: + name: search-redis + key: password + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + storage: + volumeClaimTemplate: + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi + +--- +apiVersion: redis.redis.opstreelabs.in/v1beta2 +kind: RedisReplication +metadata: + name: chat-redis + namespace: juwan +spec: + clusterSize: 1 + kubernetesConfig: + image: quay.io/opstree/redis:v7.0.15 + imagePullPolicy: IfNotPresent + resources: + requests: + cpu: 50m + memory: 64Mi + redisSecret: + name: chat-redis + key: password + podSecurityContext: + runAsUser: 1000 + fsGroup: 1000 + storage: + volumeClaimTemplate: + spec: + accessModes: ["ReadWriteOnce"] + resources: + requests: + storage: 1Gi diff --git a/deploy/k01/02-service/authz-adapter.yaml b/deploy/k01/02-service/authz-adapter.yaml new file mode 100644 index 0000000..ffbb798 --- /dev/null +++ b/deploy/k01/02-service/authz-adapter.yaml @@ -0,0 +1,48 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: authz-adapter + namespace: juwan + labels: + app: authz-adapter +spec: + replicas: 1 + selector: + matchLabels: + app: authz-adapter + template: + metadata: + labels: + app: authz-adapter + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: authz-adapter + image: registry.juwan.xhttp.zip/juwan/authz-adapter:latest + ports: + - name: grpc + containerPort: 9002 + env: + - name: LISTEN_ON + value: "0.0.0.0:9002" + - name: USER_RPC_TARGET + value: "user-rpc-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: authz-adapter-svc + namespace: juwan +spec: + ports: + - name: grpc + port: 9002 + targetPort: 9002 + selector: + app: authz-adapter diff --git a/deploy/k01/02-service/chat.yaml b/deploy/k01/02-service/chat.yaml new file mode 100644 index 0000000..09f6f03 --- /dev/null +++ b/deploy/k01/02-service/chat.yaml @@ -0,0 +1,97 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: chat-api + namespace: juwan + labels: + app: chat-api +spec: + replicas: 1 + selector: + matchLabels: + app: chat-api + template: + metadata: + labels: + app: chat-api + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: chat-api + image: registry.juwan.xhttp.zip/juwan/chat-api:latest + ports: + - name: http + containerPort: 8888 + - name: ws + containerPort: 8889 + - name: wt + containerPort: 8443 + hostPort: 8443 + protocol: UDP + - name: metrics + containerPort: 4001 + env: + - name: MONGO_PASSWORD + valueFrom: + secretKeyRef: + name: chat-mongodb-app-user-password + key: password + - name: MONGO_URI + value: "mongodb://app-user:$(MONGO_PASSWORD)@chat-mongodb-0.chat-mongodb-svc.juwan.svc.cluster.local:27017/juwan_chat?replicaSet=chat-mongodb&authSource=admin" + - name: MONGO_DATABASE + value: juwan_chat + - name: REDIS_HOST + value: chat-redis-master.juwan + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: chat-redis + key: password + - name: JWT_SECRET_KEY + valueFrom: + secretKeyRef: + name: jwt-secret + key: secret-key + - name: CHAT_WT_CERT_FILE + value: "/etc/certs/tls.crt" + - name: CHAT_WT_KEY_FILE + value: "/etc/certs/tls.key" + volumeMounts: + - name: certs + mountPath: /etc/certs + readOnly: true + resources: + requests: + cpu: 20m + memory: 32Mi + volumes: + - name: certs + secret: + secretName: chat-wt-tls + +--- +apiVersion: v1 +kind: Service +metadata: + name: chat-api-svc + namespace: juwan +spec: + ports: + - name: http + port: 8888 + targetPort: 8888 + - name: ws + port: 8889 + targetPort: 8889 + - name: wt + port: 8443 + targetPort: 8443 + protocol: UDP + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: chat-api diff --git a/deploy/k01/02-service/community.yaml b/deploy/k01/02-service/community.yaml new file mode 100644 index 0000000..5710d5e --- /dev/null +++ b/deploy/k01/02-service/community.yaml @@ -0,0 +1,136 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: community-rpc + namespace: juwan + labels: + app: community-rpc +spec: + replicas: 1 + selector: + matchLabels: + app: community-rpc + template: + metadata: + labels: + app: community-rpc + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: community-rpc + image: registry.juwan.xhttp.zip/juwan/community-rpc:latest + ports: + - name: grpc + containerPort: 8080 + - name: metrics + containerPort: 4001 + env: + - name: PD_USERNAME + valueFrom: + secretKeyRef: + name: community-db-app + key: username + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: community-db-app + key: password + - name: DB_NAME + valueFrom: + secretKeyRef: + name: community-db-app + key: dbname + - name: DB_HOST + value: community-db-rw.juwan + - name: DB_HOST_RO + value: community-db-ro.juwan + - name: DB_PORT + value: "5432" + - name: REDIS_HOST + value: community-redis-master.juwan + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: community-redis + key: password + - name: SNOWFLAKE_RPC_TARGET + value: "snowflake-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: community-rpc-svc + namespace: juwan +spec: + ports: + - name: grpc + port: 8080 + targetPort: 8080 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: community-rpc + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: community-api + namespace: juwan + labels: + app: community-api +spec: + replicas: 1 + selector: + matchLabels: + app: community-api + template: + metadata: + labels: + app: community-api + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: community-api + image: registry.juwan.xhttp.zip/juwan/community-api:latest + ports: + - name: http + containerPort: 8888 + - name: metrics + containerPort: 4001 + env: + - name: COMMUNITY_RPC_TARGET + value: "community-rpc-svc.juwan:8080" + - name: USER_RPC_TARGET + value: "user-rpc-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: community-api-svc + namespace: juwan +spec: + ports: + - name: http + port: 8888 + targetPort: 8888 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: community-api diff --git a/deploy/k01/02-service/dispute.yaml b/deploy/k01/02-service/dispute.yaml new file mode 100644 index 0000000..4219ad9 --- /dev/null +++ b/deploy/k01/02-service/dispute.yaml @@ -0,0 +1,138 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dispute-rpc + namespace: juwan + labels: + app: dispute-rpc +spec: + replicas: 1 + selector: + matchLabels: + app: dispute-rpc + template: + metadata: + labels: + app: dispute-rpc + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: dispute-rpc + image: registry.juwan.xhttp.zip/juwan/dispute-rpc:latest + ports: + - name: grpc + containerPort: 8080 + - name: metrics + containerPort: 4001 + env: + - name: PD_USERNAME + valueFrom: + secretKeyRef: + name: dispute-db-app + key: username + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: dispute-db-app + key: password + - name: DB_NAME + valueFrom: + secretKeyRef: + name: dispute-db-app + key: dbname + - name: DB_HOST + value: dispute-db-rw.juwan + - name: DB_HOST_RO + value: dispute-db-ro.juwan + - name: DB_PORT + value: "5432" + - name: REDIS_HOST + value: dispute-redis-master.juwan + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: dispute-redis + key: password + - name: SNOWFLAKE_RPC_TARGET + value: "snowflake-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: dispute-rpc-svc + namespace: juwan +spec: + ports: + - name: grpc + port: 8080 + targetPort: 8080 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: dispute-rpc + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: dispute-api + namespace: juwan + labels: + app: dispute-api +spec: + replicas: 1 + selector: + matchLabels: + app: dispute-api + template: + metadata: + labels: + app: dispute-api + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: dispute-api + image: registry.juwan.xhttp.zip/juwan/dispute-api:latest + ports: + - name: http + containerPort: 8888 + - name: metrics + containerPort: 4001 + env: + - name: DISPUTE_RPC_TARGET + value: "dispute-rpc-svc.juwan:8080" + - name: ORDER_RPC_TARGET + value: "order-rpc-svc.juwan:8080" + - name: PLAYER_RPC_TARGET + value: "player-rpc-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: dispute-api-svc + namespace: juwan +spec: + ports: + - name: http + port: 8888 + targetPort: 8888 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: dispute-api diff --git a/deploy/k01/02-service/email.yaml b/deploy/k01/02-service/email.yaml new file mode 100644 index 0000000..3e712be --- /dev/null +++ b/deploy/k01/02-service/email.yaml @@ -0,0 +1,143 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: email-api + namespace: juwan + labels: + app: email-api +spec: + replicas: 1 + selector: + matchLabels: + app: email-api + template: + metadata: + labels: + app: email-api + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: email-api + image: registry.juwan.xhttp.zip/juwan/email-api:latest + ports: + - name: http + containerPort: 8888 + - name: metrics + containerPort: 4001 + env: + - name: REDIS_HOST + value: user-redis-master.juwan + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: user-redis + key: password + - name: KAFKA_BROKER + value: "juwan-kafka-kafka-bootstrap.kafka:9092" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: email-api-svc + namespace: juwan +spec: + ports: + - name: http + port: 8888 + targetPort: 8888 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: email-api + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: email-mq + namespace: juwan + labels: + app: email-mq +spec: + replicas: 1 + selector: + matchLabels: + app: email-mq + template: + metadata: + labels: + app: email-mq + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: email-mq + image: registry.juwan.xhttp.zip/juwan/email-mq:latest + ports: + - name: metrics + containerPort: 4001 + env: + - name: KAFKA_BROKER + value: "juwan-kafka-kafka-bootstrap.kafka:9092" + - name: EMAIL_SMTP_HOST + valueFrom: + secretKeyRef: + name: email-smtp + key: host + - name: EMAIL_SMTP_PORT + valueFrom: + secretKeyRef: + name: email-smtp + key: port + - name: EMAIL_SMTP_USERNAME + valueFrom: + secretKeyRef: + name: email-smtp + key: username + - name: EMAIL_SMTP_PASSWORD + valueFrom: + secretKeyRef: + name: email-smtp + key: password + - name: EMAIL_FROM_ADDRESS + valueFrom: + secretKeyRef: + name: email-smtp + key: from-address + - name: EMAIL_FROM_NAME + valueFrom: + secretKeyRef: + name: email-smtp + key: from-name + - name: EMAIL_REPLY_TO + valueFrom: + secretKeyRef: + name: email-smtp + key: reply-to + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: email-mq-svc + namespace: juwan +spec: + ports: + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: email-mq diff --git a/deploy/k01/02-service/frontend.yaml b/deploy/k01/02-service/frontend.yaml new file mode 100644 index 0000000..af31ea1 --- /dev/null +++ b/deploy/k01/02-service/frontend.yaml @@ -0,0 +1,43 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: frontend + namespace: juwan + labels: + app: frontend +spec: + replicas: 1 + selector: + matchLabels: + app: frontend + template: + metadata: + labels: + app: frontend + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: frontend + image: registry.juwan.xhttp.zip/juwan/frontend:latest + ports: + - name: http + containerPort: 3000 + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: frontend-svc + namespace: juwan +spec: + ports: + - name: http + port: 3000 + targetPort: 3000 + selector: + app: frontend diff --git a/deploy/k01/02-service/game.yaml b/deploy/k01/02-service/game.yaml new file mode 100644 index 0000000..f51c3c6 --- /dev/null +++ b/deploy/k01/02-service/game.yaml @@ -0,0 +1,134 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: game-rpc + namespace: juwan + labels: + app: game-rpc +spec: + replicas: 1 + selector: + matchLabels: + app: game-rpc + template: + metadata: + labels: + app: game-rpc + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: game-rpc + image: registry.juwan.xhttp.zip/juwan/game-rpc:latest + ports: + - name: grpc + containerPort: 8080 + - name: metrics + containerPort: 4001 + env: + - name: PD_USERNAME + valueFrom: + secretKeyRef: + name: game-db-app + key: username + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: game-db-app + key: password + - name: DB_NAME + valueFrom: + secretKeyRef: + name: game-db-app + key: dbname + - name: DB_HOST + value: game-db-rw.juwan + - name: DB_HOST_RO + value: game-db-ro.juwan + - name: DB_PORT + value: "5432" + - name: REDIS_HOST + value: game-redis-master.juwan + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: game-redis + key: password + - name: SNOWFLAKE_RPC_TARGET + value: "snowflake-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: game-rpc-svc + namespace: juwan +spec: + ports: + - name: grpc + port: 8080 + targetPort: 8080 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: game-rpc + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: game-api + namespace: juwan + labels: + app: game-api +spec: + replicas: 1 + selector: + matchLabels: + app: game-api + template: + metadata: + labels: + app: game-api + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: game-api + image: registry.juwan.xhttp.zip/juwan/game-api:latest + ports: + - name: http + containerPort: 8888 + - name: metrics + containerPort: 4001 + env: + - name: GAME_RPC_TARGET + value: "game-rpc-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: game-api-svc + namespace: juwan +spec: + ports: + - name: http + port: 8888 + targetPort: 8888 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: game-api diff --git a/deploy/k01/02-service/notification.yaml b/deploy/k01/02-service/notification.yaml new file mode 100644 index 0000000..8d31687 --- /dev/null +++ b/deploy/k01/02-service/notification.yaml @@ -0,0 +1,134 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: notification-rpc + namespace: juwan + labels: + app: notification-rpc +spec: + replicas: 1 + selector: + matchLabels: + app: notification-rpc + template: + metadata: + labels: + app: notification-rpc + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: notification-rpc + image: registry.juwan.xhttp.zip/juwan/notification-rpc:latest + ports: + - name: grpc + containerPort: 8080 + - name: metrics + containerPort: 4001 + env: + - name: PD_USERNAME + valueFrom: + secretKeyRef: + name: notification-db-app + key: username + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: notification-db-app + key: password + - name: DB_NAME + valueFrom: + secretKeyRef: + name: notification-db-app + key: dbname + - name: DB_HOST + value: notification-db-rw.juwan + - name: DB_HOST_RO + value: notification-db-ro.juwan + - name: DB_PORT + value: "5432" + - name: REDIS_HOST + value: notification-redis-master.juwan + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: notification-redis + key: password + - name: SNOWFLAKE_RPC_TARGET + value: "snowflake-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: notification-rpc-svc + namespace: juwan +spec: + ports: + - name: grpc + port: 8080 + targetPort: 8080 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: notification-rpc + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: notification-api + namespace: juwan + labels: + app: notification-api +spec: + replicas: 1 + selector: + matchLabels: + app: notification-api + template: + metadata: + labels: + app: notification-api + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: notification-api + image: registry.juwan.xhttp.zip/juwan/notification-api:latest + ports: + - name: http + containerPort: 8888 + - name: metrics + containerPort: 4001 + env: + - name: NOTIFICATION_RPC_TARGET + value: "notification-rpc-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: notification-api-svc + namespace: juwan +spec: + ports: + - name: http + port: 8888 + targetPort: 8888 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: notification-api diff --git a/deploy/k01/02-service/objectstory.yaml b/deploy/k01/02-service/objectstory.yaml new file mode 100644 index 0000000..2907ac1 --- /dev/null +++ b/deploy/k01/02-service/objectstory.yaml @@ -0,0 +1,127 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: objectstory-rpc + namespace: juwan + labels: + app: objectstory-rpc +spec: + replicas: 1 + selector: + matchLabels: + app: objectstory-rpc + template: + metadata: + labels: + app: objectstory-rpc + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: objectstory-rpc + image: registry.juwan.xhttp.zip/juwan/objectstory-rpc:latest + ports: + - name: grpc + containerPort: 8080 + - name: metrics + containerPort: 4001 + env: + - name: S3_ENDPOINT + valueFrom: + secretKeyRef: + name: objectstory-s3 + key: endpoint + - name: S3_ACCESS_KEY + valueFrom: + secretKeyRef: + name: objectstory-s3 + key: access-key + - name: S3_SECRET_KEY + valueFrom: + secretKeyRef: + name: objectstory-s3 + key: secret-key + - name: S3_BUCKET_NAME + valueFrom: + secretKeyRef: + name: objectstory-s3 + key: bucket + - name: S3_REGION + valueFrom: + secretKeyRef: + name: objectstory-s3 + key: region + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: objectstory-rpc-svc + namespace: juwan +spec: + ports: + - name: grpc + port: 8080 + targetPort: 8080 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: objectstory-rpc + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: objectstory-api + namespace: juwan + labels: + app: objectstory-api +spec: + replicas: 1 + selector: + matchLabels: + app: objectstory-api + template: + metadata: + labels: + app: objectstory-api + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: objectstory-api + image: registry.juwan.xhttp.zip/juwan/objectstory-api:latest + ports: + - name: http + containerPort: 8888 + - name: metrics + containerPort: 4001 + env: + - name: OBJECTSTORY_RPC_TARGET + value: "objectstory-rpc-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: objectstory-api-svc + namespace: juwan +spec: + ports: + - name: http + port: 8888 + targetPort: 8888 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: objectstory-api diff --git a/deploy/k01/02-service/order.yaml b/deploy/k01/02-service/order.yaml new file mode 100644 index 0000000..bab3c64 --- /dev/null +++ b/deploy/k01/02-service/order.yaml @@ -0,0 +1,138 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: order-rpc + namespace: juwan + labels: + app: order-rpc +spec: + replicas: 1 + selector: + matchLabels: + app: order-rpc + template: + metadata: + labels: + app: order-rpc + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: order-rpc + image: registry.juwan.xhttp.zip/juwan/order-rpc:latest + ports: + - name: grpc + containerPort: 8080 + - name: metrics + containerPort: 4001 + env: + - name: PD_USERNAME + valueFrom: + secretKeyRef: + name: order-db-app + key: username + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: order-db-app + key: password + - name: DB_NAME + valueFrom: + secretKeyRef: + name: order-db-app + key: dbname + - name: DB_HOST + value: order-db-rw.juwan + - name: DB_HOST_RO + value: order-db-ro.juwan + - name: DB_PORT + value: "5432" + - name: REDIS_HOST + value: order-redis-master.juwan + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: order-redis + key: password + - name: SNOWFLAKE_RPC_TARGET + value: "snowflake-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: order-rpc-svc + namespace: juwan +spec: + ports: + - name: grpc + port: 8080 + targetPort: 8080 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: order-rpc + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: order-api + namespace: juwan + labels: + app: order-api +spec: + replicas: 1 + selector: + matchLabels: + app: order-api + template: + metadata: + labels: + app: order-api + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: order-api + image: registry.juwan.xhttp.zip/juwan/order-api:latest + ports: + - name: http + containerPort: 8888 + - name: metrics + containerPort: 4001 + env: + - name: ORDER_RPC_TARGET + value: "order-rpc-svc.juwan:8080" + - name: PLAYER_RPC_TARGET + value: "player-rpc-svc.juwan:8080" + - name: SHOP_RPC_TARGET + value: "shop-rpc-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: order-api-svc + namespace: juwan +spec: + ports: + - name: http + port: 8888 + targetPort: 8888 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: order-api diff --git a/deploy/k01/02-service/player.yaml b/deploy/k01/02-service/player.yaml new file mode 100644 index 0000000..5c06eeb --- /dev/null +++ b/deploy/k01/02-service/player.yaml @@ -0,0 +1,136 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: player-rpc + namespace: juwan + labels: + app: player-rpc +spec: + replicas: 1 + selector: + matchLabels: + app: player-rpc + template: + metadata: + labels: + app: player-rpc + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: player-rpc + image: registry.juwan.xhttp.zip/juwan/player-rpc:latest + ports: + - name: grpc + containerPort: 8080 + - name: metrics + containerPort: 4001 + env: + - name: PD_USERNAME + valueFrom: + secretKeyRef: + name: player-db-app + key: username + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: player-db-app + key: password + - name: DB_NAME + valueFrom: + secretKeyRef: + name: player-db-app + key: dbname + - name: DB_HOST + value: player-db-rw.juwan + - name: DB_HOST_RO + value: player-db-ro.juwan + - name: DB_PORT + value: "5432" + - name: REDIS_HOST + value: player-redis-master.juwan + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: player-redis + key: password + - name: SNOWFLAKE_RPC_TARGET + value: "snowflake-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: player-rpc-svc + namespace: juwan +spec: + ports: + - name: grpc + port: 8080 + targetPort: 8080 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: player-rpc + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: player-api + namespace: juwan + labels: + app: player-api +spec: + replicas: 1 + selector: + matchLabels: + app: player-api + template: + metadata: + labels: + app: player-api + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: player-api + image: registry.juwan.xhttp.zip/juwan/player-api:latest + ports: + - name: http + containerPort: 8888 + - name: metrics + containerPort: 4001 + env: + - name: PLAYER_RPC_TARGET + value: "player-rpc-svc.juwan:8080" + - name: USER_RPC_TARGET + value: "user-rpc-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: player-api-svc + namespace: juwan +spec: + ports: + - name: http + port: 8888 + targetPort: 8888 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: player-api diff --git a/deploy/k01/02-service/review.yaml b/deploy/k01/02-service/review.yaml new file mode 100644 index 0000000..c3a5251 --- /dev/null +++ b/deploy/k01/02-service/review.yaml @@ -0,0 +1,138 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: review-rpc + namespace: juwan + labels: + app: review-rpc +spec: + replicas: 1 + selector: + matchLabels: + app: review-rpc + template: + metadata: + labels: + app: review-rpc + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: review-rpc + image: registry.juwan.xhttp.zip/juwan/review-rpc:latest + ports: + - name: grpc + containerPort: 8080 + - name: metrics + containerPort: 4001 + env: + - name: PD_USERNAME + valueFrom: + secretKeyRef: + name: review-db-app + key: username + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: review-db-app + key: password + - name: DB_NAME + valueFrom: + secretKeyRef: + name: review-db-app + key: dbname + - name: DB_HOST + value: review-db-rw.juwan + - name: DB_HOST_RO + value: review-db-ro.juwan + - name: DB_PORT + value: "5432" + - name: REDIS_HOST + value: review-redis-master.juwan + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: review-redis + key: password + - name: SNOWFLAKE_RPC_TARGET + value: "snowflake-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: review-rpc-svc + namespace: juwan +spec: + ports: + - name: grpc + port: 8080 + targetPort: 8080 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: review-rpc + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: review-api + namespace: juwan + labels: + app: review-api +spec: + replicas: 1 + selector: + matchLabels: + app: review-api + template: + metadata: + labels: + app: review-api + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: review-api + image: registry.juwan.xhttp.zip/juwan/review-api:latest + ports: + - name: http + containerPort: 8888 + - name: metrics + containerPort: 4001 + env: + - name: ORDER_RPC_TARGET + value: "order-rpc-svc.juwan:8080" + - name: PLAYER_RPC_TARGET + value: "player-rpc-svc.juwan:8080" + - name: REVIEW_RPC_TARGET + value: "review-rpc-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: review-api-svc + namespace: juwan +spec: + ports: + - name: http + port: 8888 + targetPort: 8888 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: review-api diff --git a/deploy/k01/02-service/search.yaml b/deploy/k01/02-service/search.yaml new file mode 100644 index 0000000..db94886 --- /dev/null +++ b/deploy/k01/02-service/search.yaml @@ -0,0 +1,134 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: search-rpc + namespace: juwan + labels: + app: search-rpc +spec: + replicas: 1 + selector: + matchLabels: + app: search-rpc + template: + metadata: + labels: + app: search-rpc + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: search-rpc + image: registry.juwan.xhttp.zip/juwan/search-rpc:latest + ports: + - name: grpc + containerPort: 8080 + - name: metrics + containerPort: 4001 + env: + - name: PD_USERNAME + valueFrom: + secretKeyRef: + name: search-db-app + key: username + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: search-db-app + key: password + - name: DB_NAME + valueFrom: + secretKeyRef: + name: search-db-app + key: dbname + - name: DB_HOST + value: search-db-rw.juwan + - name: DB_HOST_RO + value: search-db-ro.juwan + - name: DB_PORT + value: "5432" + - name: REDIS_HOST + value: search-redis-master.juwan + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: search-redis + key: password + - name: SNOWFLAKE_RPC_TARGET + value: "snowflake-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: search-rpc-svc + namespace: juwan +spec: + ports: + - name: grpc + port: 8080 + targetPort: 8080 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: search-rpc + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: search-api + namespace: juwan + labels: + app: search-api +spec: + replicas: 1 + selector: + matchLabels: + app: search-api + template: + metadata: + labels: + app: search-api + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: search-api + image: registry.juwan.xhttp.zip/juwan/search-api:latest + ports: + - name: http + containerPort: 8888 + - name: metrics + containerPort: 4001 + env: + - name: SEARCH_RPC_TARGET + value: "search-rpc-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: search-api-svc + namespace: juwan +spec: + ports: + - name: http + port: 8888 + targetPort: 8888 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: search-api diff --git a/deploy/k01/02-service/shop.yaml b/deploy/k01/02-service/shop.yaml new file mode 100644 index 0000000..64a5652 --- /dev/null +++ b/deploy/k01/02-service/shop.yaml @@ -0,0 +1,138 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: shop-rpc + namespace: juwan + labels: + app: shop-rpc +spec: + replicas: 1 + selector: + matchLabels: + app: shop-rpc + template: + metadata: + labels: + app: shop-rpc + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: shop-rpc + image: registry.juwan.xhttp.zip/juwan/shop-rpc:latest + ports: + - name: grpc + containerPort: 8080 + - name: metrics + containerPort: 4001 + env: + - name: PD_USERNAME + valueFrom: + secretKeyRef: + name: shop-db-app + key: username + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: shop-db-app + key: password + - name: DB_NAME + valueFrom: + secretKeyRef: + name: shop-db-app + key: dbname + - name: DB_HOST + value: shop-db-rw.juwan + - name: DB_HOST_RO + value: shop-db-ro.juwan + - name: DB_PORT + value: "5432" + - name: REDIS_HOST + value: shop-redis-master.juwan + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: shop-redis + key: password + - name: SNOWFLAKE_RPC_TARGET + value: "snowflake-svc.juwan:8080" + - name: USER_RPC_TARGET + value: "user-rpc-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: shop-rpc-svc + namespace: juwan +spec: + ports: + - name: grpc + port: 8080 + targetPort: 8080 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: shop-rpc + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: shop-api + namespace: juwan + labels: + app: shop-api +spec: + replicas: 1 + selector: + matchLabels: + app: shop-api + template: + metadata: + labels: + app: shop-api + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: shop-api + image: registry.juwan.xhttp.zip/juwan/shop-api:latest + ports: + - name: http + containerPort: 8888 + - name: metrics + containerPort: 4001 + env: + - name: PLAYER_RPC_TARGET + value: "player-rpc-svc.juwan:8080" + - name: SHOP_RPC_TARGET + value: "shop-rpc-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: shop-api-svc + namespace: juwan +spec: + ports: + - name: http + port: 8888 + targetPort: 8888 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: shop-api diff --git a/deploy/k01/02-service/snowflake.yaml b/deploy/k01/02-service/snowflake.yaml new file mode 100644 index 0000000..ce53e0e --- /dev/null +++ b/deploy/k01/02-service/snowflake.yaml @@ -0,0 +1,43 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: snowflake + namespace: juwan + labels: + app: snowflake +spec: + replicas: 1 + selector: + matchLabels: + app: snowflake + template: + metadata: + labels: + app: snowflake + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: snowflake + image: registry.juwan.xhttp.zip/juwan/snowflake-rpc:latest + ports: + - name: grpc + containerPort: 8080 + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: snowflake-svc + namespace: juwan +spec: + ports: + - name: grpc + port: 8080 + targetPort: 8080 + selector: + app: snowflake diff --git a/deploy/k01/02-service/user-verifications.yaml b/deploy/k01/02-service/user-verifications.yaml new file mode 100644 index 0000000..7c0ce23 --- /dev/null +++ b/deploy/k01/02-service/user-verifications.yaml @@ -0,0 +1,83 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: user-verifications-rpc + namespace: juwan + labels: + app: user-verifications-rpc +spec: + replicas: 1 + selector: + matchLabels: + app: user-verifications-rpc + template: + metadata: + labels: + app: user-verifications-rpc + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: user-verifications-rpc + image: registry.juwan.xhttp.zip/juwan/user_verifications-rpc:latest + ports: + - name: grpc + containerPort: 8080 + - name: metrics + containerPort: 4001 + env: + - name: PD_USERNAME + valueFrom: + secretKeyRef: + name: user-db-app + key: username + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: user-db-app + key: password + - name: DB_NAME + valueFrom: + secretKeyRef: + name: user-db-app + key: dbname + - name: DB_HOST + value: user-db-rw.juwan + - name: DB_HOST_RO + value: user-db-ro.juwan + - name: DB_PORT + value: "5432" + - name: REDIS_HOST + value: user-redis-master.juwan + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: user-redis + key: password + - name: SNOWFLAKE_RPC_TARGET + value: "snowflake-svc.juwan:8080" + - name: USER_RPC_TARGET + value: "user-rpc-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: user-verifications-rpc-svc + namespace: juwan +spec: + ports: + - name: grpc + port: 8080 + targetPort: 8080 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: user-verifications-rpc diff --git a/deploy/k01/02-service/user.yaml b/deploy/k01/02-service/user.yaml new file mode 100644 index 0000000..0e57e11 --- /dev/null +++ b/deploy/k01/02-service/user.yaml @@ -0,0 +1,156 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: user-rpc + namespace: juwan + labels: + app: user-rpc +spec: + replicas: 1 + selector: + matchLabels: + app: user-rpc + template: + metadata: + labels: + app: user-rpc + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: user-rpc + image: registry.juwan.xhttp.zip/juwan/users-rpc:latest + ports: + - name: grpc + containerPort: 8080 + - name: metrics + containerPort: 4001 + env: + - name: PD_USERNAME + valueFrom: + secretKeyRef: + name: user-db-app + key: username + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: user-db-app + key: password + - name: DB_NAME + valueFrom: + secretKeyRef: + name: user-db-app + key: dbname + - name: DB_HOST + value: user-db-rw.juwan + - name: DB_HOST_RO + value: user-db-ro.juwan + - name: DB_PORT + value: "5432" + - name: REDIS_HOST + value: user-redis-master.juwan + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: user-redis + key: password + - name: SNOWFLAKE_RPC_TARGET + value: "snowflake-svc.juwan:8080" + - name: ADMIN_USERNAME + valueFrom: + secretKeyRef: + name: admin-bootstrap + key: username + - name: ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: admin-bootstrap + key: password + - name: ADMIN_EMAIL + valueFrom: + secretKeyRef: + name: admin-bootstrap + key: email + - name: JWT_SECRET_KEY + valueFrom: + secretKeyRef: + name: jwt-secret + key: secret-key + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: user-rpc-svc + namespace: juwan +spec: + ports: + - name: grpc + port: 8080 + targetPort: 8080 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: user-rpc + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: user-api + namespace: juwan + labels: + app: user-api +spec: + replicas: 1 + selector: + matchLabels: + app: user-api + template: + metadata: + labels: + app: user-api + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: user-api + image: registry.juwan.xhttp.zip/juwan/users-api:latest + ports: + - name: http + containerPort: 8888 + - name: metrics + containerPort: 4001 + env: + - name: USER_RPC_TARGET + value: "user-rpc-svc.juwan:8080" + - name: USER_VERIFICATIONS_RPC_TARGET + value: "user-verifications-rpc-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: user-api-svc + namespace: juwan +spec: + ports: + - name: http + port: 8888 + targetPort: 8888 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: user-api diff --git a/deploy/k01/02-service/wallet.yaml b/deploy/k01/02-service/wallet.yaml new file mode 100644 index 0000000..26147fb --- /dev/null +++ b/deploy/k01/02-service/wallet.yaml @@ -0,0 +1,134 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: wallet-rpc + namespace: juwan + labels: + app: wallet-rpc +spec: + replicas: 1 + selector: + matchLabels: + app: wallet-rpc + template: + metadata: + labels: + app: wallet-rpc + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: wallet-rpc + image: registry.juwan.xhttp.zip/juwan/wallet-rpc:latest + ports: + - name: grpc + containerPort: 8080 + - name: metrics + containerPort: 4001 + env: + - name: PD_USERNAME + valueFrom: + secretKeyRef: + name: wallet-db-app + key: username + - name: DB_PASSWORD + valueFrom: + secretKeyRef: + name: wallet-db-app + key: password + - name: DB_NAME + valueFrom: + secretKeyRef: + name: wallet-db-app + key: dbname + - name: DB_HOST + value: wallet-db-rw.juwan + - name: DB_HOST_RO + value: wallet-db-ro.juwan + - name: DB_PORT + value: "5432" + - name: REDIS_HOST + value: wallet-redis-master.juwan + - name: REDIS_PORT + value: "6379" + - name: REDIS_PASSWORD + valueFrom: + secretKeyRef: + name: wallet-redis + key: password + - name: SNOWFLAKE_RPC_TARGET + value: "snowflake-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: wallet-rpc-svc + namespace: juwan +spec: + ports: + - name: grpc + port: 8080 + targetPort: 8080 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: wallet-rpc + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: wallet-api + namespace: juwan + labels: + app: wallet-api +spec: + replicas: 1 + selector: + matchLabels: + app: wallet-api + template: + metadata: + labels: + app: wallet-api + spec: + imagePullSecrets: + - name: registry-creds + containers: + - name: wallet-api + image: registry.juwan.xhttp.zip/juwan/wallet-api:latest + ports: + - name: http + containerPort: 8888 + - name: metrics + containerPort: 4001 + env: + - name: WALLET_RPC_TARGET + value: "wallet-rpc-svc.juwan:8080" + resources: + requests: + cpu: 20m + memory: 32Mi + +--- +apiVersion: v1 +kind: Service +metadata: + name: wallet-api-svc + namespace: juwan +spec: + ports: + - name: http + port: 8888 + targetPort: 8888 + - name: metrics + port: 4001 + targetPort: 4001 + selector: + app: wallet-api diff --git a/deploy/k01/README.md b/deploy/k01/README.md new file mode 100644 index 0000000..9e34ea2 --- /dev/null +++ b/deploy/k01/README.md @@ -0,0 +1,118 @@ +# k01 业务集群部署 + +承载 juwan-backend 全部业务的 k3s 单节点集群(演示阶段),后续可扩 k02 / k03。 + +## 架构层次 + +| 层 | 组件 | +|---|---| +| 控制面 | k3s server(已禁用内置 traefik) | +| Operator | CloudNativePG / Strimzi Kafka / Ot-Container-Kit Redis / MongoDB Community | +| 数据 | 11 CNPG Cluster / 12 RedisReplication / Strimzi KRaft Kafka 1 broker / MongoDBCommunity 单实例 | +| 网络 | envoy-gateway(NodePort 30080)/ ratelimit + rl-redis | +| 业务 | snowflake、authz-adapter、12 rpc、14 api、email-mq、frontend | + +## 入口路径 + +``` +juwan.xhttp.zip + ├─ /wt/* → center Caddy → k01 chat-api UDP 8443(hostPort) + └─ 其他 → center Caddy → k01 envoy-gateway TCP 30080 +``` + +## 前置条件 + +- Ubuntu 26.04 LTS,root +- center 已部署,registry.juwan.xhttp.zip 可推可拉 +- DNS:`juwan.xhttp.zip` A 记录指向 k01(140.82.15.92) +- 仓库已复制到 `/root/juwan-backend` + +## 首次部署 + +```bash +cd /root/juwan-backend/deploy/k01 + +# 1. zot admin 密码写到文件供 install-k3s 读取 +echo "" > /root/registry-password +chmod 600 /root/registry-password + +# 2. 装 k3s + 4 个 Operator +bash install-k3s.sh + +# 3. 准备 .env,填入 zot 凭据 / brevo SMTP / garage S3 凭据等 +cp .env.example .env +nano .env + +# 4. 应用 namespace + RBAC,生成所有 k8s Secret +kubectl apply -f 00-base/ +bash secrets.sh + +# 5. 应用基础设施 +kubectl apply -f 01-infra/postgres.yaml +kubectl apply -f 01-infra/redis.yaml +kubectl apply -f 01-infra/mongo.yaml +kubectl apply -f 01-infra/kafka.yaml +kubectl apply -f 01-infra/ratelimit.yaml +kubectl apply -f 01-infra/envoy.yaml + +# 等所有 CNPG Cluster Ready,灌入 schema + fixture +bash 01-infra/load-schema.sh + +# 6. 应用业务服务 +kubectl apply -f 02-service/ + +# 7. 观察 pod +kubectl -n juwan get pods -w +``` + +## 凭据管理 + +`secrets.sh` 生成的全部明文密码写入 `secrets/` 目录,`chmod 600`,`.gitignore` 已排除。 + +| Secret | 用途 | +|---|---| +| `registry-creds` | imagePullSecret(zot) | +| `jwt-secret` | user-rpc 签发 / 校验 JWT | +| `admin-bootstrap` | user-rpc 启动时插入 admin 账号 | +| `email-smtp` | email-mq 发邮件 | +| `objectstory-s3` | objectstory-rpc 接 garage | +| `chat-wt-tls` | chat-api WT 自签证书(来自 `deploy/dev/certs`) | +| `-redis` | 12 个 RedisReplication 的 password | +| `chat-mongodb-app-user-password` | MongoDB SCRAM 密码 | +| `-app` | CNPG 自动生成的 PG 凭据 | + +## 已知限制 + +- snowflake 使用 Deployment + WorkerId=0。扩到多副本前需让 snowflake 业务代码支持从 env 读 WorkerId。 +- chat-api UDP 8443 走 hostPort,扩 k02/k03 时新 node 需开放 UDP 8443,DNS 也要做轮询或 LB。 +- email-api 复用 user-redis 实例(验证码 key 与 user-rpc 共享读写),跟 dev 行为一致。 +- HPA 暂不部署。加副本前把 `replicas: 1` 改大或加 HPA。 + +## 加节点(k02 / k03) + +```bash +# 在 k01 取 token +cat /var/lib/rancher/k3s/server/node-token + +# 在 k02 上 +curl -sfL https://get.k3s.io | \ + K3S_URL=https://140.82.15.92:6443 K3S_TOKEN= \ + sh - + +# 复制 registries.yaml +scp root@140.82.15.92:/etc/rancher/k3s/registries.yaml \ + /etc/rancher/k3s/registries.yaml +systemctl restart k3s-agent +``` + +## 与 center 协同 + +| 事项 | 哪一边 | +|---|---| +| `juwan.xhttp.zip` LE 证书 | center Caddy 自动签 | +| WebTransport 终结 | center Caddy(PR 7669 fork) | +| WebTransport 上游 | k01 chat-api UDP 8443(hostPort) | +| envoy-gateway 上游 | k01 NodePort 30080 | +| 镜像拉取 | k01 containerd → registry.juwan.xhttp.zip | +| S3 后端 | k01 objectstory-rpc → s3.juwan.xhttp.zip → center Garage | +| CD 触发 | gitea Actions runner(在 center) → kubectl 远程操作 k01 | diff --git a/deploy/k01/install-k3s.sh b/deploy/k01/install-k3s.sh new file mode 100755 index 0000000..5adc696 --- /dev/null +++ b/deploy/k01/install-k3s.sh @@ -0,0 +1,78 @@ +#!/usr/bin/env bash +set -euo pipefail + +REGISTRY_HOST="registry.juwan.xhttp.zip" +CNPG_VERSION="1.29.0" +STRIMZI_VERSION="1.0.0" +REDIS_OP_VERSION="0.24.0" +MONGODB_OP_VERSION="1.8.0" + +if ! command -v kubectl >/dev/null 2>&1; then + curl -sfL https://get.k3s.io | \ + INSTALL_K3S_EXEC="--disable=traefik --write-kubeconfig-mode=644" \ + sh - +fi + +if ! command -v helm >/dev/null 2>&1; then + curl -fsSL https://packages.buildkite.com/helm-linux/helm-debian/gpgkey | \ + gpg --dearmor -o /usr/share/keyrings/helm.gpg + echo "deb [signed-by=/usr/share/keyrings/helm.gpg] https://packages.buildkite.com/helm-linux/helm-debian/any/ any main" \ + > /etc/apt/sources.list.d/helm-stable-debian.list + apt-get update + apt-get install -y helm +fi + +if [ ! -f /root/registry-password ]; then + echo "need /root/registry-password (zot admin password)" >&2 + exit 1 +fi + +mkdir -p /etc/rancher/k3s +cat > /etc/rancher/k3s/registries.yaml </dev/null 2>&1; do sleep 2; done + +K01_DIR="$(cd "$(dirname "$0")" && pwd)" +kubectl apply -f "${K01_DIR}/00-base/" + +kubectl apply -f \ + "https://github.com/cloudnative-pg/cloudnative-pg/releases/download/v${CNPG_VERSION}/cnpg-${CNPG_VERSION}.yaml" + +kubectl create namespace kafka 2>/dev/null || true +kubectl apply -n kafka \ + -f "https://github.com/strimzi/strimzi-kafka-operator/releases/download/${STRIMZI_VERSION}/strimzi-cluster-operator-${STRIMZI_VERSION}.yaml" + +helm repo add ot-helm https://ot-container-kit.github.io/helm-charts/ 2>/dev/null || true +helm repo add mongodb https://mongodb.github.io/helm-charts 2>/dev/null || true +helm repo update + +helm upgrade --install redis-operator ot-helm/redis-operator \ + --version "${REDIS_OP_VERSION}" \ + --namespace redis-operator --create-namespace + +helm upgrade --install mongodb-kubernetes mongodb/mongodb-kubernetes \ + --version "${MONGODB_OP_VERSION}" \ + --namespace mongodb-operator --create-namespace \ + --set operator.watchNamespace=juwan + +kubectl -n cnpg-system rollout status deploy/cnpg-controller-manager --timeout=300s +kubectl -n kafka rollout status deploy/strimzi-cluster-operator --timeout=300s +kubectl -n redis-operator rollout status deploy/redis-operator --timeout=300s +kubectl -n mongodb-operator rollout status deploy/mongodb-kubernetes-operator --timeout=300s + +echo +echo "k3s + 4 operators ready" diff --git a/deploy/k01/secrets.sh b/deploy/k01/secrets.sh new file mode 100755 index 0000000..5a9ff9d --- /dev/null +++ b/deploy/k01/secrets.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +set -euo pipefail + +K01_DIR="$(cd "$(dirname "$0")" && pwd)" +cd "$K01_DIR" + +if [ ! -f .env ]; then + echo ".env not found, copy from .env.example and fill in" >&2 + exit 1 +fi + +set -a +. ./.env +set +a + +mkdir -p secrets +chmod 700 secrets + +write_secret() { + local name="$1" value="$2" + printf '%s\n' "$value" > "secrets/$name" + chmod 600 "secrets/$name" +} + +JWT_SECRET_KEY="${JWT_SECRET_KEY:-$(openssl rand -hex 32)}" +ADMIN_PASSWORD="${ADMIN_PASSWORD:-$(openssl rand -hex 16)}" +write_secret jwt-secret "$JWT_SECRET_KEY" +write_secret admin-password "$ADMIN_PASSWORD" + +export KUBECONFIG=/etc/rancher/k3s/k3s.yaml + +kubectl -n juwan create secret docker-registry registry-creds \ + --docker-server="${REGISTRY_HOST}" \ + --docker-username="${REGISTRY_USERNAME}" \ + --docker-password="${REGISTRY_PASSWORD}" \ + --dry-run=client -o yaml | kubectl apply -f - + +kubectl -n juwan create secret generic jwt-secret \ + --from-literal=secret-key="$JWT_SECRET_KEY" \ + --dry-run=client -o yaml | kubectl apply -f - + +kubectl -n juwan create secret generic admin-bootstrap \ + --from-literal=username="${ADMIN_USERNAME}" \ + --from-literal=password="$ADMIN_PASSWORD" \ + --from-literal=email="${ADMIN_EMAIL}" \ + --dry-run=client -o yaml | kubectl apply -f - + +kubectl -n juwan create secret generic email-smtp \ + --from-literal=host="${EMAIL_SMTP_HOST}" \ + --from-literal=port="${EMAIL_SMTP_PORT}" \ + --from-literal=username="${EMAIL_SMTP_USERNAME}" \ + --from-literal=password="${EMAIL_SMTP_PASSWORD}" \ + --from-literal=from-address="${EMAIL_FROM_ADDRESS}" \ + --from-literal=from-name="${EMAIL_FROM_NAME}" \ + --from-literal=reply-to="${EMAIL_REPLY_TO:-}" \ + --dry-run=client -o yaml | kubectl apply -f - + +kubectl -n juwan create secret generic objectstory-s3 \ + --from-literal=endpoint="${S3_ENDPOINT}" \ + --from-literal=access-key="${S3_ACCESS_KEY}" \ + --from-literal=secret-key="${S3_SECRET_KEY}" \ + --from-literal=bucket="${S3_BUCKET_NAME}" \ + --from-literal=region="${S3_REGION}" \ + --dry-run=client -o yaml | kubectl apply -f - + +DEV_CERTS="$(cd "$K01_DIR/../dev/certs" && pwd)" +kubectl -n juwan create secret tls chat-wt-tls \ + --cert="${DEV_CERTS}/tls.crt" \ + --key="${DEV_CERTS}/tls.key" \ + --dry-run=client -o yaml | kubectl apply -f - + +DOMAINS=(user player game shop order wallet community review dispute notification search chat) +for d in "${DOMAINS[@]}"; do + pwd_val="$(openssl rand -hex 16)" + write_secret "redis-${d}-password" "$pwd_val" + kubectl -n juwan create secret generic "${d}-redis" \ + --from-literal=password="$pwd_val" \ + --dry-run=client -o yaml | kubectl apply -f - +done + +MONGO_PASSWORD="${MONGO_PASSWORD:-$(openssl rand -hex 16)}" +write_secret mongo-password "$MONGO_PASSWORD" +kubectl -n juwan create secret generic chat-mongodb-app-user-password \ + --from-literal=password="$MONGO_PASSWORD" \ + --dry-run=client -o yaml | kubectl apply -f - + +echo +echo "secrets/ written, k8s Secrets applied to namespace juwan" +echo "admin password: $ADMIN_PASSWORD"