ಕುಬರ್ನೆಟ್ಸ್ ಸಲಹೆಗಳು ಮತ್ತು ತಂತ್ರಗಳು: NGINX ಪ್ರವೇಶದಲ್ಲಿ ಕಸ್ಟಮ್ ದೋಷ ಪುಟಗಳು

ಕುಬರ್ನೆಟ್ಸ್ ಸಲಹೆಗಳು ಮತ್ತು ತಂತ್ರಗಳು: NGINX ಪ್ರವೇಶದಲ್ಲಿ ಕಸ್ಟಮ್ ದೋಷ ಪುಟಗಳು

ಈ ಲೇಖನದಲ್ಲಿ, ನಾನು ವೈಯಕ್ತಿಕಗೊಳಿಸಿದ ದೋಷ ಪುಟಗಳನ್ನು ಪ್ರದರ್ಶಿಸಲು ಸಂಬಂಧಿಸಿದ NGINX ಪ್ರವೇಶದ ಎರಡು ವೈಶಿಷ್ಟ್ಯಗಳ ಬಗ್ಗೆ ಮಾತನಾಡಲು ಬಯಸುತ್ತೇನೆ, ಹಾಗೆಯೇ ಅವುಗಳಲ್ಲಿ ಇರುವ ಮಿತಿಗಳು ಮತ್ತು ಅವುಗಳ ಸುತ್ತಲೂ ಕೆಲಸ ಮಾಡುವ ವಿಧಾನಗಳು.

1. ಡೀಫಾಲ್ಟ್ ಬ್ಯಾಕೆಂಡ್ ಅನ್ನು ಬದಲಾಯಿಸುವುದು

ಪೂರ್ವನಿಯೋಜಿತವಾಗಿ, NGINX ಪ್ರವೇಶವು ಡೀಫಾಲ್ಟ್ ಬ್ಯಾಕೆಂಡ್ ಅನ್ನು ಬಳಸುತ್ತದೆ, ಇದು ಅನುಗುಣವಾದ ಕಾರ್ಯವನ್ನು ನಿರ್ವಹಿಸುತ್ತದೆ. ಇದರರ್ಥ ಪ್ರವೇಶ ಸಂಪನ್ಮೂಲಗಳಲ್ಲಿಲ್ಲದ ಹೋಸ್ಟ್ ಅನ್ನು ಸೂಚಿಸುವ ಪ್ರವೇಶವನ್ನು ವಿನಂತಿಸುವಾಗ, ನಾವು 404 ಪ್ರತಿಕ್ರಿಯೆ ಕೋಡ್‌ನೊಂದಿಗೆ ಕೆಳಗಿನ ಪುಟವನ್ನು ಸ್ವೀಕರಿಸುತ್ತೇವೆ:

ಕುಬರ್ನೆಟ್ಸ್ ಸಲಹೆಗಳು ಮತ್ತು ತಂತ್ರಗಳು: NGINX ಪ್ರವೇಶದಲ್ಲಿ ಕಸ್ಟಮ್ ದೋಷ ಪುಟಗಳು

ಆದಾಗ್ಯೂ, ಹೆಚ್ಚು ಹೆಚ್ಚಾಗಿ ನಮ್ಮ ಗ್ರಾಹಕರು ತಮ್ಮ ಪುಟವನ್ನು ಸ್ಟ್ಯಾಂಡರ್ಡ್ 404 ಬದಲಿಗೆ ಕಾರ್ಪೊರೇಟ್ ಲೋಗೋ ಮತ್ತು ಇತರ ಸೌಕರ್ಯಗಳೊಂದಿಗೆ ತೋರಿಸಲು ವಿನಂತಿಯೊಂದಿಗೆ ಬರುತ್ತಾರೆ. ಇದನ್ನು ಮಾಡಲು, NGINX ಪ್ರವೇಶವನ್ನು ಹೊಂದಿದೆ ಅಂತರ್ನಿರ್ಮಿತ ಸಾಮರ್ಥ್ಯ ಮರುವ್ಯಾಖ್ಯಾನಿಸಿ default-backend-service. ನಾವು ಫಾರ್ಮ್ಯಾಟ್ ನಮೂದನ್ನು ಅದೇ ಹೆಸರಿನ ಆಯ್ಕೆಗೆ ಆರ್ಗ್ಯುಮೆಂಟ್ ಆಗಿ ರವಾನಿಸುತ್ತೇವೆ namespace/servicename. ಸೇವೆಯ ಪೋರ್ಟ್ 80 ಆಗಿರಬೇಕು.

ಇದನ್ನು ಮಾಡಲು, ನಿಮ್ಮ ಅಪ್ಲಿಕೇಶನ್‌ನೊಂದಿಗೆ ನಿಮ್ಮ ಸ್ವಂತ ಪಾಡ್ (ನಿಯೋಜನೆ) ಮತ್ತು ಸೇವೆಯನ್ನು ನೀವು ರಚಿಸಬೇಕಾಗಿದೆ (YAML ನಲ್ಲಿ ಅನುಷ್ಠಾನದ ಉದಾಹರಣೆ ingress-nginx ರೆಪೊಸಿಟರಿಯಿಂದ), ಇದನ್ನು ಡೀಫಾಲ್ಟ್ ಬ್ಯಾಕೆಂಡ್ ಬದಲಿಗೆ ನೀಡಲಾಗುತ್ತದೆ.

ಒಂದು ಸಣ್ಣ ವಿವರಣೆ ಇಲ್ಲಿದೆ:

~$ curl -i -XGET http://sadsdasdas.kube-cloud.my/
HTTP/1.1 404 Not Found
Date: Mon, 11 Mar 2019 05:38:15 GMT
Content-Type: */*
Transfer-Encoding: chunked
Connection: keep-alive

<span>The page you're looking for could not be found.</span>

ಆದ್ದರಿಂದ YAML ಮೂಲಕ ಸ್ಪಷ್ಟವಾಗಿ ರಚಿಸದ ಎಲ್ಲಾ ಡೊಮೇನ್‌ಗಳು kind: Ingress, ಡೀಫಾಲ್ಟ್ ಬ್ಯಾಕೆಂಡ್‌ಗೆ ಬೀಳುತ್ತದೆ. ಮೇಲಿನ ಪಟ್ಟಿಯಲ್ಲಿ, ಈ ಡೊಮೇನ್ ಆಯಿತು sadsdasdas.

2. ಡೀಫಾಲ್ಟ್ ಬ್ಯಾಕೆಂಡ್ ಅನ್ನು ಬಳಸಿಕೊಂಡು ಅಪ್ಲಿಕೇಶನ್‌ನಲ್ಲಿ HTTP ದೋಷಗಳನ್ನು ನಿರ್ವಹಿಸುವುದು

ಮತ್ತೊಂದು ಸನ್ನಿವೇಶವು HTTP ದೋಷಗಳಲ್ಲಿ ಕೊನೆಗೊಳ್ಳುವ ವಿನಂತಿಗಳು (404, 500, 502...) ಅಂತಹ ಸಂದರ್ಭಗಳನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸದ ಅಪ್ಲಿಕೇಶನ್‌ಗೆ (ಅನುಗುಣವಾದ ಸುಂದರವಾದ ಪುಟಗಳನ್ನು ರಚಿಸಲಾಗಿಲ್ಲ). ಬಹು ಅಪ್ಲಿಕೇಶನ್‌ಗಳಲ್ಲಿ ಒಂದೇ ದೋಷ ಪುಟಗಳನ್ನು ಪೂರೈಸಲು ಡೆವಲಪರ್‌ಗಳ ಬಯಕೆಯೂ ಇದಕ್ಕೆ ಕಾರಣವಾಗಿರಬಹುದು.

ಸರ್ವರ್ ಬದಿಯಲ್ಲಿ ಈ ಪ್ರಕರಣವನ್ನು ಕಾರ್ಯಗತಗೊಳಿಸಲು ನಮಗೆ ಅಗತ್ಯವಿದೆ:

  1. ಡೀಫಾಲ್ಟ್ ಬ್ಯಾಕೆಂಡ್ ಬಗ್ಗೆ ಪ್ಯಾರಾಗ್ರಾಫ್‌ನಿಂದ ಮೇಲಿನ ಸೂಚನೆಗಳನ್ನು ಅನುಸರಿಸಿ;
  2. nginx-ingress ಕಾನ್ಫಿಗರೇಶನ್ ConfigMap ಗೆ ಕೀಲಿಯನ್ನು ಸೇರಿಸಿ custom-http-errors, ಉದಾಹರಣೆಗೆ, ಮೌಲ್ಯದೊಂದಿಗೆ 404,503 (ಹೊಸ ನಿಯಮದಿಂದ ಒಳಗೊಳ್ಳುವ ದೋಷ ಸಂಕೇತಗಳಿಗೆ ನಿಸ್ಸಂಶಯವಾಗಿ ಅನುರೂಪವಾಗಿದೆ).

ನಿರೀಕ್ಷಿತ ಫಲಿತಾಂಶವನ್ನು ಸಾಧಿಸಲಾಗಿದೆ: ಕ್ಲೈಂಟ್ ಅಪ್ಲಿಕೇಶನ್ ಚಾಲನೆಯಲ್ಲಿರುವಾಗ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ ಕೋಡ್ 404 ಅಥವಾ 503 ನೊಂದಿಗೆ ದೋಷವನ್ನು ಸ್ವೀಕರಿಸಿದಾಗ, ವಿನಂತಿಯನ್ನು ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಹೊಸ ಡೀಫಾಲ್ಟ್ ಬ್ಯಾಕೆಂಡ್‌ಗೆ ಮರುನಿರ್ದೇಶಿಸಲಾಗುತ್ತದೆ...

ಆದಾಗ್ಯೂ, ಡೀಫಾಲ್ಟ್ ಬ್ಯಾಕೆಂಡ್ ಮತ್ತು ಕಸ್ಟಮ್-http-ದೋಷಗಳಿಗಾಗಿ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಅಭಿವೃದ್ಧಿಪಡಿಸುವಾಗ, ನೀವು ಪ್ರಮುಖ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಗಣನೆಗೆ ತೆಗೆದುಕೊಳ್ಳಬೇಕಾಗುತ್ತದೆ:

!!! Important The custom backend is expected to return the correct HTTP status code instead of 200. NGINX does not change the response from the custom default backend.

ಸತ್ಯವೆಂದರೆ ವಿನಂತಿಯನ್ನು ಮರುನಿರ್ದೇಶಿಸಿದಾಗ, ಹಿಂದಿನ ಪ್ರತಿಕ್ರಿಯೆ ಕೋಡ್ ಮತ್ತು ಹೆಚ್ಚುವರಿ ಮಾಹಿತಿಯೊಂದಿಗೆ ಹೆಡರ್ ಉಪಯುಕ್ತ ಮಾಹಿತಿಯನ್ನು ಹೊಂದಿರುತ್ತದೆ (ಅವುಗಳ ಸಂಪೂರ್ಣ ಪಟ್ಟಿ ಲಭ್ಯವಿದೆ ಇಲ್ಲಿ).

ಇದರರ್ಥ ನೀವೇ ಮಾಡಬೇಕು ಸರಿಯಾದ ಪ್ರತಿಕ್ರಿಯೆ ಕೋಡ್ ಅನ್ನು ನೋಡಿಕೊಳ್ಳಿ. ಇಲ್ಲಿ ಒಂದು ಉದಾಹರಣೆ ಇದೆ ಇದು ಹೇಗೆ ಕೆಲಸ ಮಾಡುತ್ತದೆ ಎಂಬುದನ್ನು ದಸ್ತಾವೇಜನ್ನು.

ವಿಭಿನ್ನ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ವಿಭಿನ್ನ ಡೀಫಾಲ್ಟ್ ಬ್ಯಾಕೆಂಡ್‌ಗಳನ್ನು ಹೊಂದಿವೆ

ಪರಿಹಾರವು ಸಂಪೂರ್ಣ ಕ್ಲಸ್ಟರ್‌ಗೆ ಜಾಗತಿಕವಾಗಿಲ್ಲ, ಆದರೆ ನಿರ್ದಿಷ್ಟ ಅಪ್ಲಿಕೇಶನ್‌ಗಳಿಗೆ ಮಾತ್ರ ಅನ್ವಯಿಸುತ್ತದೆ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಲು, ನೀವು ಮೊದಲು ಪ್ರವೇಶದ ಆವೃತ್ತಿಯನ್ನು ಪರಿಶೀಲಿಸಬೇಕು. ಅದು ಹೊಂದಾಣಿಕೆಯಾದರೆ 0.23 ಅಥವಾ ಹೆಚ್ಚಿನದು, ಸ್ಥಳೀಯ ಪ್ರವೇಶ ಟಿಪ್ಪಣಿಗಳನ್ನು ಬಳಸಿ:

  1. ನಾವು ಅತಿಕ್ರಮಿಸಬಹುದು default-backend ಗೆ ಪ್ರತಿಯೊಂದರಲ್ಲೂ ಪ್ರವೇಶ ನ ಟಿಪ್ಪಣಿಗಳನ್ನು ಬಳಸುವುದು;
  2. ನಾವು ಅತಿಕ್ರಮಿಸಬಹುದು custom-http-errors ಗೆ ಪ್ರತಿಯೊಂದರಲ್ಲೂ ಪ್ರವೇಶ ನ ಟಿಪ್ಪಣಿಗಳನ್ನು ಬಳಸುವುದು.

ಪರಿಣಾಮವಾಗಿ, ಪ್ರವೇಶ ಸಂಪನ್ಮೂಲವು ಈ ರೀತಿ ಕಾಣುತ್ತದೆ:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: {{ .Chart.Name }}-app2
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/custom-http-errors: "404,502"
    nginx.ingress.kubernetes.io/default-backend: error-pages
spec:
  tls:
  - hosts:
    - app2.example.com
    secretName: wildcard-tls
  rules:
  - host: app2.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: {{ .Chart.Name }}-app2
          servicePort: 80

ಈ ಸಂದರ್ಭದಲ್ಲಿ, 404 ಮತ್ತು 502 ದೋಷಗಳನ್ನು ಎಲ್ಲಾ ಅಗತ್ಯ ಹೆಡರ್‌ಗಳೊಂದಿಗೆ ದೋಷ ಪುಟಗಳ ಸೇವೆಗೆ ಮರುನಿರ್ದೇಶಿಸಲಾಗುತ್ತದೆ.

В Ingress ನ ಹಿಂದಿನ ಆವೃತ್ತಿಗಳು ಈ ವೈಶಿಷ್ಟ್ಯವನ್ನು ಹೊಂದಿರಲಿಲ್ಲ (0.23 ನಲ್ಲಿ ಅದೃಷ್ಟದ ಬದ್ಧತೆ) ಮತ್ತು ನಿಮ್ಮ ಕ್ಲಸ್ಟರ್‌ನಲ್ಲಿ ನೀವು 2 ಸಂಪೂರ್ಣವಾಗಿ ವಿಭಿನ್ನ ಅಪ್ಲಿಕೇಶನ್‌ಗಳನ್ನು ಚಲಾಯಿಸುತ್ತಿದ್ದರೆ ಮತ್ತು ಅವುಗಳಲ್ಲಿ ಪ್ರತಿಯೊಂದಕ್ಕೂ ವಿಭಿನ್ನ ಡೀಫಾಲ್ಟ್-ಬ್ಯಾಕೆಂಡ್-ಸೇವೆ ಮತ್ತು ಸಂಸ್ಕರಣೆಯನ್ನು ನೀವು ನಿರ್ದಿಷ್ಟಪಡಿಸಲು ಬಯಸಿದರೆ, ಇದಕ್ಕಾಗಿ ನೀವು ಪರಿಹಾರಗಳನ್ನು ಬಳಸಬೇಕಾಗುತ್ತದೆ, ಅದರಲ್ಲಿ ನಾವು ಎರಡು ಹೊಂದಿದ್ದೇವೆ.

ಪ್ರವೇಶ <0.23: ಒಂದನ್ನು ಸಮೀಪಿಸಿ

ಈ ಆಯ್ಕೆಯು ಸರಳವಾಗಿದೆ. ಅದರ ಪುಟಗಳಿಗೆ ಸೇವೆ ಸಲ್ಲಿಸುವ ಅಪ್ಲಿಕೇಶನ್‌ನಂತೆ, ನಾವು ಸಾಮಾನ್ಯ HTML ಅನ್ನು ಹೊಂದಿದ್ದೇವೆ, ಇದು ಹೆಡರ್‌ಗಳನ್ನು ಹೇಗೆ ನೋಡಬೇಕು ಮತ್ತು ಸರಿಯಾದ ಪ್ರತಿಕ್ರಿಯೆ ಕೋಡ್‌ಗಳನ್ನು ಹಿಂದಿರುಗಿಸುವುದು ಹೇಗೆ ಎಂದು ತಿಳಿದಿಲ್ಲ. ಅಂತಹ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು url ನಿಂದ ಪ್ರವೇಶದೊಂದಿಗೆ ಹೊರತರಲಾಗಿದೆ /error-pages, ಮತ್ತು ಕ್ಯಾಟಲಾಗ್‌ನಲ್ಲಿ ws ಹಿಂತಿರುಗಿದ HTML ಆಗಿರುತ್ತದೆ.

YAML ನಲ್ಲಿ ವಿವರಣೆ:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: {{ .Chart.Name }}-app2
  annotations:
    kubernetes.io/ingress.class: "nginx"
    ingress.kubernetes.io/server-snippet: |
      proxy_intercept_errors on;
      error_page 500 501 502 503 504 @error_pages;
      location @error_pages {
        rewrite ^ /error-pages/other/index.html break;
        proxy_pass http://error-pages.prod.svc.cluster.local;
      }
spec:
  tls:
  - hosts:
    - app2.example.com
    secretName: wildcard-tls
  rules:
  - host: app2.example.com
    http:
      paths:
      - path: /
        backend:
          serviceName: {{ .Chart.Name }}-app2
          servicePort: 80

ಈ ನಿಯೋಜನೆಗಾಗಿ ಸೇವೆಯು ClusterIP ಪ್ರಕಾರವಾಗಿರಬೇಕು.

ಅದೇ ಸಮಯದಲ್ಲಿ, ನಾವು ದೋಷವನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸುವ ಅಪ್ಲಿಕೇಶನ್‌ನಲ್ಲಿ, ಪ್ರವೇಶದಲ್ಲಿ ನಾವು ಈ ಕೆಳಗಿನ ವಿಷಯದೊಂದಿಗೆ ಸರ್ವರ್-ಸ್ನಿಪ್ಪೆಟ್ ಅಥವಾ ಕಾನ್ಫಿಗರೇಶನ್-ಸ್ನಿಪ್ಪೆಟ್ ಅನ್ನು ಸೇರಿಸುತ್ತೇವೆ:

nginx.ingress.kubernetes.io    /server-snippet: |
      proxy_intercept_errors on;
      error_page 500 501 502 503 504 @error_pages;
      location @error_pages {
        rewrite ^ /error-pages/ws/index.html break;
        proxy_pass http://error-pages.prod.svc.cluster.local;
      }

ಪ್ರವೇಶ <0.23: ಎರಡನೇ ವಿಧಾನ

ಹೆಡರ್‌ಗಳನ್ನು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಬಹುದಾದ ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಒಂದು ಆಯ್ಕೆ... ಮತ್ತು ಸಾಮಾನ್ಯವಾಗಿ ಇದು ಹೆಚ್ಚು ಸರಿಯಾದ ಮಾರ್ಗವಾಗಿದೆ, ಕಸ್ಟಮ್-http-ದೋಷಗಳಿಂದ ಎರವಲು ಪಡೆಯಲಾಗಿದೆ. ಇದನ್ನು ಹಸ್ತಚಾಲಿತವಾಗಿ ಬಳಸುವುದು (ನಕಲು ಮಾಡುವುದು) ಜಾಗತಿಕ ಸೆಟ್ಟಿಂಗ್‌ಗಳನ್ನು ಬದಲಾಯಿಸದಿರಲು ನಿಮಗೆ ಅನುಮತಿಸುತ್ತದೆ.

ಹಂತಗಳು ಈ ಕೆಳಗಿನಂತಿವೆ. ನಾವು ರಚಿಸುತ್ತೇವೆ ಅದೇ ನಿಯೋಜನೆ ಅಗತ್ಯವಿರುವ ಮುಖ್ಯಾಂಶಗಳನ್ನು ಆಲಿಸುವ ಮತ್ತು ಸರಿಯಾಗಿ ಪ್ರತಿಕ್ರಿಯಿಸುವ ಅಪ್ಲಿಕೇಶನ್‌ನೊಂದಿಗೆ. ಕೆಳಗಿನ ವಿಷಯದೊಂದಿಗೆ ಪ್ರವೇಶ ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಸರ್ವರ್-ತುಣುಕು ಸೇರಿಸಿ:

nginx.ingress.kubernetes.io    /server-snippet: |
      proxy_intercept_errors off;
      error_page 404 = @custom_404;
      error_page 503 = @custom_503;
      location @custom_404 {
        internal;
        proxy_intercept_errors off;
        proxy_set_header       X-Code             404;
        proxy_set_header       X-Format           $http_accept;
        proxy_set_header       X-Original-URI     $request_uri;
        proxy_set_header       X-Namespace        $namespace;
        proxy_set_header       X-Ingress-Name     $ingress_name;
        proxy_set_header       X-Service-Name     $service_name;
        proxy_set_header       X-Service-Port     $service_port;
        proxy_set_header       Host               $best_http_host;
        rewrite ^ /error-pages/ws/index.html break;
        proxy_pass http://error-pages.prod.svc.cluster.local;
      }
      location @custom_503 {
        internal;
        proxy_intercept_errors off;
        proxy_set_header       X-Code             503;
        proxy_set_header       X-Format           $http_accept;
        proxy_set_header       X-Original-URI     $request_uri;
        proxy_set_header       X-Namespace        $namespace;
        proxy_set_header       X-Ingress-Name     $ingress_name;
        proxy_set_header       X-Service-Name     $service_name;
        proxy_set_header       X-Service-Port     $service_port;
        proxy_set_header       Host               $best_http_host;
        rewrite ^ /error-pages/ws/index.html break;
        proxy_pass http://error-pages.prod.svc.cluster.local;
      }

ನೀವು ನೋಡುವಂತೆ, ನಾವು ಪ್ರಕ್ರಿಯೆಗೊಳಿಸಲು ಬಯಸುವ ಪ್ರತಿಯೊಂದು ದೋಷಕ್ಕೂ, ನಾವು ನಮ್ಮದೇ ಆದ ಸ್ಥಳವನ್ನು ಮಾಡಬೇಕಾಗಿದೆ, ಅಲ್ಲಿ "ಸ್ಥಳೀಯ" ಒಂದರಂತೆ ಎಲ್ಲಾ ಅಗತ್ಯ ಹೆಡರ್ಗಳನ್ನು ಸೇರಿಸಲಾಗುತ್ತದೆ. ಕಸ್ಟಮ್-ದೋಷ-ಪುಟಗಳು. ಈ ರೀತಿಯಾಗಿ ನಾವು ಪ್ರತ್ಯೇಕ ಸ್ಥಳಗಳು ಮತ್ತು ಸರ್ವರ್‌ಗಳಿಗೆ ಸಹ ವಿಭಿನ್ನ ವೈಯಕ್ತೀಕರಿಸಿದ ದೋಷ ಪುಟಗಳನ್ನು ರಚಿಸಬಹುದು.

ಪಿಎಸ್

K8s ಸಲಹೆಗಳು ಮತ್ತು ತಂತ್ರಗಳ ಸರಣಿಯಿಂದ ಇತರೆ:

ನಮ್ಮ ಬ್ಲಾಗ್‌ನಲ್ಲಿಯೂ ಓದಿ:

ಮೂಲ: www.habr.com

ಕಾಮೆಂಟ್ ಅನ್ನು ಸೇರಿಸಿ