استخدام TLS مع وحدة تحكم الدخول على خدمة Azure Kubernetes (AKS)

يستخدم بروتوكول أمان طبقة النقل (TLS) الشهادات لتوفير الأمان للاتصال والتشفير والمصادقة والتكامل. يتيح لك استخدام TLS مع وحدة تحكم الدخول على AKS تأمين الاتصال بين تطبيقاتك وتجربة فوائد وحدة تحكم الدخول.

يمكنك إحضار الشهادات الخاصة بك ودمجها مع برنامج تشغيل Secrets Store CSI. بدلا من ذلك، يمكنك استخدام cert-manager، الذي يقوم تلقائيا بإنشاء وتكوين شهادات Let's Encrypt . يتم تشغيل تطبيقين في نظام مجموعة AKS، يمكن الوصول إلى كل منهما عبر عنوان IP واحد.

هام

يوصى بالوظيفة الإضافية لتوجيه التطبيق للدخول في AKS. لمزيد من المعلومات، راجع Nginx Ingress المدار مع الوظيفة الإضافية لتوجيه التطبيق.

هام

لا تدير Microsoft أو تدعم مدير الشهادات وأي مشكلات تنشأ عن استخدامها. للاطلاع على المشكلات المتعلقة بمدير الشهادات، راجع وثائق استكشاف الأخطاء وإصلاحها لمدير الشهادات.

هناك نوعان من وحدات التحكم في الدخول الخاصة بالمصدر المفتوح لـ Kubernetes تعتمد على Nginx: أحدهما يحتفظ به مجتمع Kubernetes (kubernetes/ingress-nginx)، والآخر تحتفظ به NGINX, Inc. (nginxinc/kubernetes-ingress). تستخدم هذه المقالة وحدة تحكم دخول مجتمع Kubernetes.

قبل البدء

  • تفترض هذه المقالة أن لديك وحدة تحكم الدخول والتطبيقات التي تم إعدادها. إذا كنت بحاجة إلى وحدة تحكم دخول أو أمثلة للتطبيقات، فشاهد إنشاء وحدة تحكم دخول.

  • يستخدم هذا المقال Helm 3 لتثبيت وحدة التحكم في دخول NGINX على إصدار معتمد من Kubernetes. تأكد من أنك تستخدم أحدث إصدار من Helm وأن لديك حق الوصول إلى ingress-nginx مستودعات Helm و jetstack . قد لا تكون الخطوات الموضحة في هذه المقالة متوافقة مع الإصدارات السابقة من مخطط Helm أو وحدة تحكم الدخول NGINX أو Kubernetes.

  • تفترض هذه المقالة أن لديك مجموعة AKS موجودة مع Azure Container Registry (ACR) متكامل. لمزيد من المعلومات حول إنشاء نظام مجموعة AKS باستخدام ACR متكامل، راجع المصادقة باستخدام ACR من AKS.

  • إذا كنت تستخدم Azure CLI، تتطلب هذه المقالة تشغيل الإصدار 2.0.64 من Azure CLI أو أحدث. قم بتشغيل az --version للعثور على الإصدار. إذا كنت بحاجة إلى التثبيت أو الترقية، فراجع تثبيت Azure CLI.

  • إذا كنت تستخدم Azure PowerShell، تتطلب هذه المقالة تشغيل Azure PowerShell الإصدار 5.9.0 أو أحدث. قم بتشغيل Get-InstalledModule -Name Az للعثور على الإصدار. إذا كنت بحاجة إلى التثبيت أو الترقية، فراجع تثبيت وحدة Azure PowerShell.

استخدام TLS مع الشهادات الخاصة بك مع Secrets Store CSI Driver

لاستخدام TLS مع الشهادات الخاصة بك مع Secrets Store CSI Driver، تحتاج إلى نظام مجموعة AKS مع تكوين برنامج تشغيل Secrets Store CSI ومثيل Azure Key Vault.

لمزيد من المعلومات، راجع إعداد برنامج تشغيل مستودع البيانات السرية Secrets Store CSI، لتمكين وحدة تحكم الدخول NGINX باستخدام TLS.

استخدام شهادات TLS مع Let's Encrypt

لاستخدام TLS مع شهادات Let's Encrypt ، ستقوم بنشر cert-manager، الذي يقوم تلقائيا بإنشاء وتكوين شهادات Let's Encrypt.

استيراد صور cert-manager المستخدمة في مخطط Helm إلى ACR الخاص بك

  • استخدم az acr import لاستيراد الصور التالية إلى ACR الخاص بك.

    REGISTRY_NAME=<REGISTRY_NAME>
    CERT_MANAGER_REGISTRY=quay.io
    CERT_MANAGER_TAG=v1.8.0
    CERT_MANAGER_IMAGE_CONTROLLER=jetstack/cert-manager-controller
    CERT_MANAGER_IMAGE_WEBHOOK=jetstack/cert-manager-webhook
    CERT_MANAGER_IMAGE_CAINJECTOR=jetstack/cert-manager-cainjector
    
    az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG
    az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG
    az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG
    

إشعار

يمكنك أيضا استيراد مخططات Helm إلى ACR الخاص بك. لمزيد من المعلومات، راجع دفع مخططات Helm وسحبها إلى ACR.

خيارات تكوين وحدة تحكم الدخول

يمكنك تكوين وحدة تحكم دخول NGINX باستخدام عنوان IP عام ثابت أو عنوان IP عام ديناميكي. إذا كنت تستخدم مجالا مخصصا، فستحتاج إلى إضافة سجل A إلى منطقة DNS. إذا كنت لا تستخدم مجالا مخصصا، يمكنك تكوين اسم مجال مؤهل بالكامل (FQDN) لعنوان IP لوحدة تحكم الدخول.

إنشاء عنوان IP عام ثابت أو ديناميكي

استخدم عنوان IP عام ثابت

يمكنك تكوين وحدة تحكم الدخول باستخدام عنوان IP عام ثابت. يبقى عنوان IP العام الثابت إذا قمت بحذف وحدة تحكم الدخول. لا يبقى عنوان IP إذا قمت بحذف نظام مجموعة AKS.

عند ترقية وحدة تحكم الدخول الخاصة بك، يجب تمرير معلمة إلى إصدار Helm للتأكد من أن خدمة وحدة التحكم في الدخول على دراية بموازن التحميل الذي سيتم تخصيصه لها. لكي تعمل شهادات HTTPS بشكل صحيح، يمكنك استخدام تسمية DNS لتكوين FQDN لعنوان IP لوحدة تحكم الدخول.

  1. احصل على اسم مجموعة الموارد لنظام مجموعة AKS باستخدام az aks show الأمر .

    az aks show --resource-group myResourceGroup --name myAKSCluster --query nodeResourceGroup -o tsv
    
  2. إنشاء عنوان IP عام باستخدام أسلوب التخصيص الثابت باستخدام az network public-ip create الأمر . ينشئ المثال التالي عنوان IP عاما يسمى myAKSPublicIP في مجموعة موارد نظام مجموعة AKS التي تم الحصول عليها في الخطوة السابقة.

    az network public-ip create --resource-group MC_myResourceGroup_myAKSCluster_eastus --name myAKSPublicIP --sku Standard --allocation-method static --query publicIp.ipAddress -o tsv
    

إشعار

بدلا من ذلك، يمكنك إنشاء عنوان IP في مجموعة موارد مختلفة، والتي يمكنك إدارتها بشكل منفصل عن مجموعة AKS الخاصة بك. إذا قمت بإنشاء عنوان IP في مجموعة موارد مختلفة، فتأكد من صحة ما يلي:

  • قام هوية نظام المجموعة المستخدمة من قبل مجموعة AKS بتفويض الأذونات لمجموعة الموارد، مثل Network Contributor .
  • إضافة المعلمة --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-resource-group"="<RESOURCE_GROUP>". استبدل <RESOURCE_GROUP> باسم مجموعة الموارد حيث يوجد عنوان IP.
  1. إضافة المعلمة --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"="<DNS_LABEL>". يمكن لتسمية DNS تعيين هذا إما عند نشر وحدة تحكم الدخول لأول مرّة، أو يمكن تكوينه لاحقا.

  2. إضافة المعلمة --set controller.service.loadBalancerIP="<STATIC_IP>". حدد عنوان IP العام الذي تم إنشائه في الخطوة السابقة.

    DNS_LABEL="<DNS_LABEL>"
    NAMESPACE="ingress-basic"
    STATIC_IP=<STATIC_IP>
    
    helm upgrade ingress-nginx ingress-nginx/ingress-nginx \
      --namespace $NAMESPACE \
      --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DNS_LABEL \
      --set controller.service.loadBalancerIP=$STATIC_IP \
      --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz
    

لمزيد من المعلومات، راجع «Use a static public IP address and DNS label with the AKS load balancer».

استخدم عنوان IP عام ديناميكي

يتم إنشاء عنوان IP عام ل Azure لوحدة تحكم الدخول عند الإنشاء. عنوان IP العام ثابت طوال عمر وحدة التحكم في الدخول. لا يبقى عنوان IP العام إذا قمت بحذف وحدة التحكم في الدخول. إذا قمت بإنشاء وحدة تحكم دخول جديدة، تعيين عنوان IP عام جديد. يجب أن يبدو الإخراج مشابها للإخراج النموذجي التالي.

  • kubectl get service استخدم الأمر للحصول على عنوان IP العام لوحدة التحكم في الدخول.

    # Get the public IP address for your ingress controller
    
    kubectl --namespace ingress-basic get services -o wide -w nginx-ingress-ingress-nginx-controller
    
    # Sample output
    
    NAME                                     TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)                      AGE   SELECTOR
    nginx-ingress-ingress-nginx-controller   LoadBalancer   10.0.74.133   EXTERNAL_IP     80:32486/TCP,443:30953/TCP   44s   app.kubernetes.io/component=controller,app.kubernetes.io/instance=nginx-ingress,app.kubernetes.io/name=ingress-nginx
    

إضافة سجل إلى منطقة DNS الخاصة بك

إذا كنت تستخدم مجالا مخصصا، فستحتاج إلى إضافة سجل A إلى منطقة DNS. إذا كنت لا تستخدم مجالا مخصصا، يمكنك تكوين عنوان IP العام باستخدام FQDN.

  • أضف سجل A إلى منطقة DNS الخاصة بك باستخدام عنوان IP الخارجي لخدمة NGINX باستخدام az network dns record-set a add-record.

    az network dns record-set a add-record \
        --resource-group myResourceGroup \
        --zone-name MY_CUSTOM_DOMAIN \
        --record-set-name "*" \
        --ipv4-address MY_EXTERNAL_IP
    

تكوين FQDN لوحدة تحكم الدخول

اختياريا، يمكنك تكوين FQDN لعنوان IP لوحدة تحكم الدخول بدلا من مجال مخصص عن طريق تعيين تسمية DNS. يجب أن يتبع FQDN هذا النموذج: <CUSTOM DNS LABEL>.<AZURE REGION NAME>.cloudapp.azure.com.

هام

يجب أن تكون تسمية DNS فريدة داخل موقع Azure الخاص بها.

يمكنك تكوين FQDN باستخدام إحدى الطرق التالية:

  • تعيين تسمية DNS باستخدام Azure CLI أو Azure PowerShell.
  • تعيين تسمية DNS باستخدام إعدادات مخطط Helm.

لمزيد من المعلومات، راجع تسميات أسماء DNS لعنوان IP العام.

تعيين تسمية DNS باستخدام Azure CLI أو Azure PowerShell

تأكد من استبدال <DNS_LABEL> بتسمية DNS الفريدة.

# Public IP address of your ingress controller
IP="MY_EXTERNAL_IP"

# Name to associate with public IP address
DNSLABEL="<DNS_LABEL>"

# Get the resource-id of the public IP
PUBLICIPID=$(az network public-ip list --query "[?ipAddress!=null]|[?contains(ipAddress, '$IP')].[id]" --output tsv)

# Update public IP address with DNS name
az network public-ip update --ids $PUBLICIPID --dns-name $DNSLABEL

# Display the FQDN
az network public-ip show --ids $PUBLICIPID --query "[dnsSettings.fqdn]" --output tsv

تعيين تسمية DNS باستخدام إعدادات مخطط Helm

يمكنك تمرير إعداد التعليق التوضيحي إلى تكوين مخطط Helm باستخدام المعلمة --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name" . يمكن تعيين هذه المعلمة عند نشر وحدة تحكم الدخول لأول مرة، أو يمكن تكوينها لاحقا.

يوضح المثال التالي كيفية تحديث هذا الإعداد بعد نشر وحدة التحكم. تأكد من استبدال <DNS_LABEL> بتسمية DNS الفريدة.

DNSLABEL="<DNS_LABEL>"
NAMESPACE="ingress-basic"

helm upgrade ingress-nginx ingress-nginx/ingress-nginx \
  --namespace $NAMESPACE \
  --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DNSLABEL \
  --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz

تثبيت مدير الشهادات «Install cert-manager»

توفر وحدة تحكم الدخول NGINX الدعم لإنهاء TLS. هناك عدة طرق لاسترداد وتكوين شهادات HTTPS. تستخدم هذه المقالة cert-manager، الذي يوفر إنشاء شهادة Lets Encrypt تلقائيا ووظائف الإدارة.

لتثبيت وحدة تحكم مدير الشهادات، استخدم الأوامر التالية.

# Set variable for ACR location to use for pulling images
ACR_URL=<REGISTRY_URL>

# Label the ingress-basic namespace to disable resource validation
kubectl label namespace ingress-basic cert-manager.io/disable-validation=true

# Add the Jetstack Helm repository
helm repo add jetstack https://charts.jetstack.io

# Update your local Helm chart repository cache
helm repo update

# Install the cert-manager Helm chart
helm install cert-manager jetstack/cert-manager \
  --namespace ingress-basic \
  --version=$CERT_MANAGER_TAG \
  --set installCRDs=true \
  --set nodeSelector."kubernetes\.io/os"=linux \
  --set image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_CONTROLLER \
  --set image.tag=$CERT_MANAGER_TAG \
  --set webhook.image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_WEBHOOK \
  --set webhook.image.tag=$CERT_MANAGER_TAG \
  --set cainjector.image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_CAINJECTOR \
  --set cainjector.image.tag=$CERT_MANAGER_TAG

لمزيد من المعلومات حول تكوين مدير الشهادات «cert-manager»، راجع مشروع cert-manager.

إنشاء مُصدر شهادات نظام مجموعة CA

قبل إصدار الشهادات، يتطلب مدير الشهادات أحد المصدرين التاليين:

  • المصدر، الذي يعمل في مساحة اسم واحدة.
  • مورد ClusterIssuer، والذي يعمل عبر جميع مساحات الأسماء.

لمزيد من المعلومات، راجع وثائق مصدر شهادات cert-manager.

  1. إنشاء مصدر الشهادة لنظام المجموعة، مثل cluster-issuer.yaml، باستخدام بيان التطبيق في المثال التالي. استبدل MY_EMAIL_ADDRESS بعنوان صالح من مؤسستك.

    apiVersion: cert-manager.io/v1
    kind: ClusterIssuer
    metadata:
      name: letsencrypt
    spec:
      acme:
        server: https://acme-v02.api.letsencrypt.org/directory
        email: MY_EMAIL_ADDRESS
        privateKeySecretRef:
          name: letsencrypt
        solvers:
        - http01:
            ingress:
              class: nginx
              podTemplate:
                spec:
                  nodeSelector:
                    "kubernetes.io/os": linux
    
  2. تطبيق المصدر باستخدام kubectl apply الأمر .

    kubectl apply -f cluster-issuer.yaml --namespace ingress-basic
    

تحديث مسارات الدخول

تحتاج إلى تحديث مسارات الدخول للتعامل مع نسبة استخدام الشبكة إلى FQDN أو المجال المخصص.

في المثال التالي، يتم توجيه حركة المرور على هذا النحو:

  • نسبة استخدام الشبكة إلى hello-world-ingress. يتم توجيه MY_CUSTOM_DOMAIN إلى خدمة aks-helloworld-one .
  • نسبة استخدام الشبكة إلى hello-world-ingress. يتم توجيه MY_CUSTOM_DOMAIN/hello-world-two إلى خدمة aks-helloworld-two .
  • يتم توجيه تدفق البيانات المتجهة إلى hello-world-ingress.MY_CUSTOM_DOMAIN/static إلى الخدمة المُسمّاة aks-helloworld-one للأصول الثابتة.

إشعار

إذا قمت بتكوين FQDN لعنوان IP وحدة تحكم الدخول بدلاً من مجال مخصص، فاستخدم FQDN بدلاً من hello-world-ingress.MY_CUSTOM_DOMAIN.

على سبيل المثال، إذا كان FQDN الخاص بك demo-aks-ingress.eastus.cloudapp.azure.com، فاستبدل hello-world-ingress. MY_CUSTOM_DOMAIN مع demo-aks-ingress.eastus.cloudapp.azure.com في hello-world-ingress.yaml.

  1. إنشاء الملف أو تحديثه hello-world-ingress.yaml باستخدام المثال التالي لملف YAML. spec.tls.hosts قم بتحديث و spec.rules.host إلى اسم DNS الذي أنشأته في خطوة سابقة.

    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: hello-world-ingress
      annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /$2
        nginx.ingress.kubernetes.io/use-regex: "true"
        cert-manager.io/cluster-issuer: letsencrypt
    spec:
      ingressClassName: nginx
      tls:
      - hosts:
        - hello-world-ingress.MY_CUSTOM_DOMAIN
        secretName: tls-secret
      rules:
      - host: hello-world-ingress.MY_CUSTOM_DOMAIN
        http:
          paths:
          - path: /hello-world-one(/|$)(.*)
            pathType: Prefix
            backend:
              service:
                name: aks-helloworld-one
                port:
                  number: 80
          - path: /hello-world-two(/|$)(.*)
            pathType: Prefix
            backend:
              service:
                name: aks-helloworld-two
                port:
                  number: 80
          - path: /(.*)
            pathType: Prefix
            backend:
              service:
                name: aks-helloworld-one
                port:
                  number: 80
    ---
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: hello-world-ingress-static
      annotations:
        nginx.ingress.kubernetes.io/ssl-redirect: "false"
        nginx.ingress.kubernetes.io/rewrite-target: /static/$2
    spec:
      ingressClassName: nginx
      tls:
      - hosts:
        - hello-world-ingress.MY_CUSTOM_DOMAIN
        secretName: tls-secret
      rules:
      - host: hello-world-ingress.MY_CUSTOM_DOMAIN
        http:
          paths:
          - path: /static(/|$)(.*)
            pathType: Prefix
            backend:
              service:
                name: aks-helloworld-one
                port:
                  number: 80
    
  2. إنشاء مورد الدخول باستخدام الأمر kubectl apply.

    kubectl apply -f hello-world-ingress.yaml --namespace ingress-basic
    

تحقق من إنشاء كائن شهادة

بعد ذلك، يجب إنشاء مورد شهادة. يعرف مورد الشهادة X.509 المطلوبة. لمزيد من المعلومات، راجع شهادات cert-manager

ينشئ Cert-manager تلقائيا كائن شهادة لك باستخدام ingress-shim، والذي يتم نشره تلقائيا مع cert-manager منذ v0.2.2. لمزيد من المعلومات، انظر وثائق «ingress-shim ».

للتحقق من إنشاء الشهادة بنجاح، استخدم kubectl get certificate --namespace ingress-basic الأمر وتحقق من أن READY هو True. قد يستغرق الأمر عدة دقائق للحصول على الإخراج.

kubectl get certificate --namespace ingress-basic

يظهر الإخراج التالي حالة الشهادة.

NAME         READY   SECRET       AGE
tls-secret   True    tls-secret   11m

اختبار تكوين الدخول

فتح متصفح ويب على hello-world-ingress.MY_CUSTOM_DOMAIN أو FQDN لوحدة تحكم الدخول Kubernetes الخاصة بك. تأكد من صحة ما يلي:

  • تتم إعادة توجيهك لاستخدام HTTPS.
  • الشهادة موثوق بها.
  • يظهر التطبيق التجريبي في مستعرض الويب.
  • أضف /hello-world-two إلى نهاية المجال وتأكد من عرض التطبيق التجريبي الثاني مع العنوان المخصص.

تنظيف الموارد

استخدمت هذه المقالة Helm لتثبيت مكونات الدخول والشهادات وتطبيقات العينة. عند نشر مخطط Helm، يتم إنشاء الكثير من موارد Kubernetes. تتضمن هذه الموارد وحدات الجراب وعمليات التوزيع والخدمات. لتنظيف هذه الموارد، يمكنك إما حذف مساحة اسم العينة بأكملها أو الموارد الفردية.

حذف مساحة اسم العينة وجميع الموارد

يؤدي حذف عينة مساحة الاسم أيضا إلى حذف كافة الموارد في مساحة الاسم.

  • احذف عينة مساحة الاسم بأكملها باستخدام kubectl delete الأمر وتحديد اسم مساحة الاسم.

    kubectl delete namespace ingress-basic
    

حذف الموارد بشكل فردي

بدلا من ذلك، يمكنك حذف المورد بشكل فردي.

  1. إزالة موارد مصدر نظام المجموعة.

    kubectl delete -f cluster-issuer.yaml --namespace ingress-basic
    
  2. أدرج إصدارات Helm بالأمر helm list. ابحث عن المخططات المسماة nginx وcert-manager، كما هو موضح في إخراج المثال التالي.

    $ helm list --namespace ingress-basic
    
    NAME                    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
    cert-manager            ingress-basic   1               2020-01-15 10:23:36.515514 -0600 CST    deployed        cert-manager-v0.13.0    v0.13.0
    nginx                   ingress-basic   1               2020-01-15 10:09:45.982693 -0600 CST    deployed        nginx-ingress-1.29.1    0.27.0
    
  3. قم بإلغاء تثبيت الإصدارات باستخدام helm uninstall الأمر . يقوم المثال التالي بإلغاء تثبيت دخول NGINX وعمليات نشر مدير الشهادات cert-manager.

    $ helm uninstall cert-manager nginx --namespace ingress-basic
    
    release "cert-manager" uninstalled
    release "nginx" uninstalled
    
  4. إزالة التطبيقين النموذجيين.

    kubectl delete -f aks-helloworld-one.yaml --namespace ingress-basic
    kubectl delete -f aks-helloworld-two.yaml --namespace ingress-basic
    
  5. قم بإزالة مسار الدخول الذي وجه نسبة استخدام الشبكة إلى نماذج التطبيقات.

    kubectl delete -f hello-world-ingress.yaml --namespace ingress-basic
    
  6. حذف مساحة الاسم نفسها. kubectl delete استخدم الأمر وحدد اسم مساحة الاسم.

    kubectl delete namespace ingress-basic
    

الخطوات التالية

تضمنت هذه المقالة بعض المكونات الخارجية لخدمة Azure Kubernetes. لمعرفة المزيد حول هذه المكونات، راجع صفحات المشروع التالية:

يمكنك أيضًا: