۱. مقدمه
گروه نقطه پایانی شبکه (NEG) اتصال سرویس خصوصی (PSC) از زنجیرهسازی یک متعادلکننده بار HTTPS داخلی با یک متعادلکننده بار HTTPS خارجی پشتیبانی میکند. این امر، بررسیهای سلامت توزیعشده و ترافیک سطح داده را با استفاده از محدودههای تعریفشده توسط مشتری به On-Prem ارائه میدهد. علاوه بر این، چندین VPC که از طریق چندین اتصال منطقهای به On-Prem متصل میشوند نیز با این توپولوژی پشتیبانی میشوند.
در این آزمایشگاه کد، نحوه پیکربندی این اتصال سرتاسری را بر اساس توپولوژی زیر نشان خواهیم داد. از چپ به راست، مشتریان در محل، یک ماشین مجازی برای شبیهسازی سرویسهای HTTP، بهرهگیری از اتصال ترکیبی (HA-VPN یا InterConnect) و NEG ترکیبی برای ارائه از طریق متعادلکننده بار داخلی HTTPS دارند. PSC از HTTPS LB داخلی به عنوان پیوستهای سرویس استفاده میکند. PSC NEG پیوستها را به عنوان سرویس backend، در معرض HTTPS LB خارجی، مصرف میکند. کاربران اینترنت میتوانند از شبکه جهانی گوگل برای تسریع دسترسی به سرویسهای HTTP On-Prem استفاده کنند.

شکل 1. سرویس خصوصی Connect از گروه نقطه پایانی شبکه و پیوستهای سرویس برای اتصال متعادلکننده بار HTTPS خارجی به متعادلکننده بار HTTPS داخلی استفاده میکند و backend را به On-Prem گسترش میدهد.
آنچه یاد خواهید گرفت
- متعادلکننده بار داخلی HTTPS با NEG ترکیبی و بررسی سلامت توزیعشده
- پیوست سرویس PSC با متعادلکننده بار داخلی HTTPS
- راهاندازی گروه نقطه پایانی شبکه PSC
- افشای PSC NEG با متعادلکننده بار خارجی HTTPS
آنچه نیاز دارید
- آشنایی با اتصال ترکیبی، مانند HA-VPN
- آشنایی با متعادلسازی بار HTTPS داخلی/خارجی
- دانش اتصال به سرویس خصوصی
۲. قبل از شروع
توجه: Codelab مراحل پیکربندی و اعتبارسنجی را بر اساس توپولوژی نشان داده شده ارائه میدهد، در صورت نیاز، رویه را برای برآورده کردن نیازهای سازمان خود تغییر دهید. مجوزهای IAM در محدوده Codelab نیستند.
Codelab از یک پروژه برای شبیهسازی کل فرآیند استفاده خواهد کرد. همچنین از چندین پروژه پشتیبانی میشود.
پروژه واحد - بهروزرسانی پروژه برای پشتیبانی از شبکه تولیدکننده و مصرفکننده
داخل Cloud Shell، مطمئن شوید که شناسه پروژه شما تنظیم شده است
gcloud config list project gcloud config set project [YOUR-PROJECT-NAME] prodproject=YOUR-PROJECT-NAME echo $prodproject
۳. منابع اولیه ایجاد کنید
در بخش بعدی، یک VPC و ماشینهای مجازی On-Premium راهاندازی خواهیم کرد تا سرویسهای On-Premium مشتری را شبیهسازی کنیم.
شبکه VPC
از پوسته ابری
gcloud compute networks create vpc-demo-onprem --project=$prodproject --subnet-mode=custom
ایجاد زیرشبکه
از پوسته ابری
gcloud compute networks subnets create vpc-demo-onprem-asia-southeast1 --project=$prodproject --range=10.0.0.0/24 --network=vpc-demo-onprem --region=asia-southeast1
ایجاد قوانین فایروال
متعادلکننده بار داخلی HTTPS از بررسی سلامت توزیعشده پشتیبانی میکند، قوانین فایروال فقط باید محدوده IP زیرشبکه پروکسی را مجاز بدانند. برای فهرست کردن پروژههای خود، سند زیر را دنبال کنید.
از Cloud Shell یک قانون فایروال ایجاد کنید تا بررسیهای سلامت backend و ترافیک سطح داده از زیرشبکههای پروکسی فعال شود.
gcloud compute firewall-rules create vpc-demo-health-checks --allow tcp:80,tcp:443 --network vpc-demo-onprem --source-ranges 10.0.3.0/24 --enable-logging
از Cloud Shell یک قانون فایروال ایجاد کنید تا به IAP اجازه اتصال به نمونههای ماشین مجازی شما را بدهد،
gcloud compute firewall-rules create psclab-iap-prod --network vpc-demo-onprem --allow tcp:22 --source-ranges=35.235.240.0/20 --enable-logging
۴. ایجاد نمونههای ماشین مجازی On-Prem
این ماشین مجازی سرویسهای داخلی را شبیهسازی میکند و باید با استفاده از NEG ترکیبی، با متعادلکننده بار داخلی HTTPS در معرض دید قرار گیرد.
از Cloud Shell نمونه www01 را ایجاد کنید
gcloud compute instances create www01 \
--zone=asia-southeast1-b \
--image-family=debian-11 \
--image-project=debian-cloud \
--network-interface=network-tier=PREMIUM,nic-type=GVNIC,stack-type=IPV4_ONLY,subnet=vpc-demo-onprem-asia-southeast1 \
--shielded-secure-boot \
--shielded-vtpm \
--shielded-integrity-monitoring \
--metadata=startup-script='#! /bin/bash
sudo apt-get update
sudo apt-get install nginx -y
vm_hostname="$(curl -H "Metadata-Flavor:Google" \
http://169.254.169.254/computeMetadata/v1/instance/name)"
filter="{print \$NF}"
vm_zone="$(curl -H "Metadata-Flavor:Google" \
http://169.254.169.254/computeMetadata/v1/instance/zone \
| awk -F/ "${filter}")"
echo "Page on $vm_hostname in $vm_zone" | \
tee /var/www/html/index.nginx-debian.html
sudo systemctl restart nginx'
در بخش بعدی، از letsencrypt برای تولید گواهینامهها و نصب روی Nginx استفاده خواهیم کرد. برای مرحله بعدی، فایل کلید عمومی و خصوصی را دانلود کنید. برای تولید گواهینامه باید پورت TCP 80 را به طور موقت به اینترنت باز کنید.
مطمئن شوید که این ماشین مجازی یک نام دامنه عمومی دارد. برای مثال، در Cloud DNS یک رکورد A [www01.yinghli.demo.altostrat.com](http://www01.yinghli.demo.altostrat.com) اضافه کنید و به آدرس IP عمومی ماشین مجازی اشاره کنید.
gcloud dns --project=$prodproject record-sets create www01.yinghli.demo.altostrat.com. --zone="yinghli-demo" --type="A" --ttl="300" --rrdatas="34.87.77.186"
از کنسول ماشین مجازی www01، دستورالعملهای نصب گواهینامهها روی Nginx را دنبال کنید و برای مراحل بعدی، یک کپی از fullchain.pem و private.pem تهیه کنید.
sudo apt install snapd sudo snap install core; sudo snap refresh core sudo snap install --classic certbot sudo ln -s /snap/bin/certbot /usr/bin/certbot sudo certbot --nginx
۵. شبکه VPC تولیدکنندگان را ایجاد کنید
توجه: پیکربندی شبکه ترکیبی در این پیکربندی لحاظ نشده است.
شبکه VPC
از پوسته ابری
gcloud compute networks create vpc-demo-producer --project=$prodproject --subnet-mode=custom
ایجاد زیرشبکه
از پوسته ابری
gcloud compute networks subnets create vpc-demo-asia-southeast1 --project=$prodproject --range=10.0.2.0/24 --network=vpc-demo-producer --region=asia-southeast1
ایجاد زیرشبکه پروکسی
از پوسته ابری
gcloud compute networks subnets create proxy-subnet-asia-southeast1 \ --purpose=REGIONAL_MANAGED_PROXY \ --role=ACTIVE \ --region=asia-southeast1 \ --network=vpc-demo-producer \ --range=10.0.3.0/24
اتصال ترکیبی
برای پیادهسازی اتصال HA-VPN بین On-Prem و Producer VPC، مستندات Cloud VPN را دنبال کنید. پیکربندی پیشفرض را روی Cloud Router حفظ کنید، نیازی به اضافه کردن ۱۳۰.۲۱۱.۰.۰/۲۲ و ۳۵.۱۹۱.۰.۰/۱۶ به تبلیغات BGP نداریم.
۶. تولیدکنندگان هیبرید NEG ایجاد کنید
یک گروه نقطه پایانی شبکه ترکیبی ایجاد کنید و IP:PORT ماشین مجازی on-premium را به NEG اضافه کنید.
از پوسته ابری
gcloud compute network-endpoint-groups create on-prem-service-neg \
--network-endpoint-type=NON_GCP_PRIVATE_IP_PORT \
--zone=asia-southeast1-b \
--network=vpc-demo-producer
gcloud compute network-endpoint-groups update on-prem-service-neg \
--zone=asia-southeast1-b \
--add-endpoint="ip=10.0.0.2,port=443"
۷. ایجاد متعادلکننده بار HTTPS داخلی برای تولیدکنندگان
در حال حاضر، متعادلکننده بار HTTPS خارجی فقط از پروتکل HTTPS به PSC NEG پشتیبانی میکند ( اسناد ). هنگام انتشار خدمات، باید از متعادلکننده بار HTTPS داخلی استفاده کنیم و دسترسی جهانی به قوانین ارسال را فعال کنیم.
از Cloud Shell، بررسی سلامت منطقهای را ایجاد کنید.
gcloud compute health-checks create https on-prem-service-hc \
--region=asia-southeast1 \
--use-serving-port
از Cloud Shell سرویس backend را ایجاد کنید و Hybrid NEG را اضافه کنید.
gcloud compute backend-services create on-premise-service-backend \ --load-balancing-scheme=INTERNAL_MANAGED \ --protocol=HTTPS \ --region=asia-southeast1 \ --health-checks=on-prem-service-hc \ --health-checks-region=asia-southeast1 gcloud compute backend-services add-backend on-premise-service-backend \ --network-endpoint-group=on-prem-service-neg \ --network-endpoint-group-zone=asia-southeast1-b \ --region=asia-southeast1 \ --balancing-mode=RATE \ --max-rate-per-endpoint=100
از Cloud Shell نقشه URL را ایجاد کنید
gcloud compute url-maps create on-premise-url \
--default-service on-premise-service-backend \
--region=asia-southeast1
از Cloud Shell گواهینامههای SSL منطقهای ایجاد کنید. دو فایل گواهینامه از ماشین مجازی دانلود میشوند.
gcloud compute ssl-certificates create www01 \
--certificate=fullchain.pem \
--private-key=private.pem \
--region=asia-southeast1
از Cloud Shell، https-target-proxy ایجاد کنید
gcloud compute target-https-proxies create on-premise-httpsproxy \
--ssl-certificates=www01 \
--url-map=on-premise-url \
--url-map-region=asia-southeast1 \
--region=asia-southeast1
از Cloud Shell یک IP استاتیک داخلی رزرو کنید و قانون ارسال را ایجاد کنید
gcloud compute addresses create ilbaddress \
--region=asia-southeast1 \
--subnet=vpc-demo-asia-southeast1 \
--addresses=10.0.2.100
gcloud compute forwarding-rules create https-ilb-psc \
--load-balancing-scheme=INTERNAL_MANAGED \
--network=vpc-demo-producer \
--subnet=vpc-demo-asia-southeast1 \
--address=ilbaddress \
--ports=443 \
--region=asia-southeast1 \
--target-https-proxy=on-premise-httpsproxy \
--target-https-proxy-region=asia-southeast1
--allow-global-access
۸. ایجاد نمونه ماشین مجازی تولیدکننده
برای تأیید، یک ماشین مجازی تولیدکننده ایجاد کنید.
از پوسته ابری
gcloud compute instances create test01 \
--zone=asia-southeast1-b \
--image-family=debian-11 \
--image-project=debian-cloud \
--network-interface=network-tier=PREMIUM,nic-type=GVNIC,stack-type=IPV4_ONLY,subnet=vpc-demo-asia-southeast1 \
--shielded-secure-boot \
--shielded-vtpm \
--shielded-integrity-monitoring
برای اینکه به IAP اجازه دهید به ماشینهای مجازی شما متصل شود، یک قانون فایروال ایجاد کنید که:
از پوسته ابری
gcloud compute firewall-rules create psclab-iap-prod --network vpc-demo-producer --allow tcp:22 --source-ranges=35.235.240.0/20 --enable-logging
از کنسول ماشین مجازی تولیدکننده، به آدرس [ www01.yinghli.demo.altostrat.com ](https://www01.yinghli.demo.altostrat.com) دسترسی پیدا کنید و آدرس IP متعادلکننده بار داخلی HTTPS را تعیین کنید. HTTP 200 نشان داد که پیکربندی طبق انتظار کار میکند.
curl -v --resolve www01.yinghli.demo.altostrat.com:443:10.0.2.100 https://www01.yinghli.demo.altostrat.com * Added www01.yinghli.demo.altostrat.com:443:10.0.2.100 to DNS cache * Hostname www01.yinghli.demo.altostrat.com was found in DNS cache * Trying 10.0.2.100:443... * Connected to www01.yinghli.demo.altostrat.com (10.0.2.100) port 443 (#0) * ALPN, offering h2 * ALPN, offering http/1.1 * successfully set certificate verify locations: * CAfile: /etc/ssl/certs/ca-certificates.crt * CApath: /etc/ssl/certs * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (IN), TLS handshake, CERT verify (15): * TLSv1.3 (IN), TLS handshake, Finished (20): * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.3 (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 * ALPN, server accepted to use h2 * Server certificate: * subject: CN=www01.yinghli.demo.altostrat.com * start date: Jun 4 10:36:43 2023 GMT * expire date: Sep 2 10:36:42 2023 GMT * subjectAltName: host "www01.yinghli.demo.altostrat.com" matched cert's "www01.yinghli.demo.altostrat.com" * issuer: C=US; O=Let's Encrypt; CN=R3 * SSL certificate verify ok. * Using HTTP2, server supports multi-use * Connection state changed (HTTP/2 confirmed) * Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0 * Using Stream ID: 1 (easy handle 0x55865ef982e0) > GET / HTTP/2 > Host: www01.yinghli.demo.altostrat.com > user-agent: curl/7.74.0 > accept: */* > * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * old SSL session ID is stale, removing * Connection state changed (MAX_CONCURRENT_STREAMS == 100)! < HTTP/2 200 < server: nginx/1.18.0 < date: Mon, 05 Jun 2023 02:29:38 GMT < content-type: text/html < content-length: 35 < last-modified: Sun, 04 Jun 2023 09:02:16 GMT < etag: "647c5318-23" < accept-ranges: bytes < via: 1.1 google < Page on www01 in asia-southeast1-b * Connection #0 to host www01.yinghli.demo.altostrat.com left intact
توجه: شما نمیتوانید مستقیماً به سرویسهای HTTPS ماشین مجازی 10.0.0.2 دسترسی داشته باشید، زیرا فایروال داخلی فقط به زیرشبکه پروکسی 10.0.3.0/24 اجازه دسترسی میدهد.
۹. ایجاد زیرشبکه PSC NAT
از پوسته ابری
gcloud compute networks subnets create psc-nat-subnet \ --network=vpc-demo-producer \ --region=asia-southeast1 \ --range=10.0.5.0/24 \ --purpose=private-service-connect
۱۰. ایجاد پیوست سرویس HTTPs
از Cloud Shell پیوست سرویس HTTPs را ایجاد کنید
gcloud compute service-attachments create ilbserviceattach \ --region=asia-southeast1 \ --producer-forwarding-rule=https-ilb-psc \ --connection-preference=ACCEPT_AUTOMATIC \ --nat-subnets=psc-nat-subnet
اعتبارسنجی پیوست سرویس HTTPs
gcloud compute service-attachments describe ilbserviceattach --region asia-southeast1
نام ضمیمه سرویس رکورد:
projects/<project>/regions/asia-southeast1/serviceAttachments/ilbserviceattach
۱۱. ایجاد شبکه VPC مصرفکنندگان
در بخش بعدی، VPC مصرفکننده در همان پروژه پیکربندی شده است، اما پروژههای مختلفی نیز پشتیبانی میشوند. ارتباط بین شبکه مصرفکننده و تولیدکننده از طریق پیوست سرویس تعریفشده در شبکه تولیدکننده انجام میشود.
شبکه VPC
از پوسته ابری
gcloud compute networks create vpc-demo-consumer --project=$prodproject --subnet-mode=custom
ایجاد زیرشبکه
از پوسته ابری
gcloud compute networks subnets create consumer-subnet --project=$prodproject --range=10.0.6.0/24 --network=vpc-demo-consumer --region=asia-southeast1
۱۲. ایجاد گروه نقطه پایانی شبکه PSC
ایجاد PSC منفی
نام پیوست سرویسهای https قبلی را کپی کرده و در پارامترهای --psc-target-service جایگذاری کنید.
از پوسته ابری
gcloud beta compute network-endpoint-groups create consumerpscneg \ --project=$prodproject \ --region=asia-southeast1 \ --network-endpoint-type=PRIVATE_SERVICE_CONNECT \ --psc-target-service=projects/<project>/regions/asia-southeast1/serviceAttachments/ilbserviceattach \ --network=vpc-demo-consumer \ --subnet=consumer-subnet
پس از راهاندازی موفقیتآمیز PSC NEG، از رابط کاربری، مسیر Private Service Connect -> Published Services -> را دنبال کنید. توجه داشته باشید که اتصال منتشر شده ilbserviceattach اکنون نشاندهنده ۱ قانون ارسال است.

۱۳. ایجاد متعادلکننده بار HTTPS خارجی برای مصرفکننده
یک متعادلکننده بار HTTPS خارجی ایجاد کنید و از PSC NEG به عنوان سرویسهای backend ( مستندات ) استفاده کنید.
از پوسته ابری
gcloud compute addresses create httpspsclb \
--ip-version=IPV4 --global
gcloud compute backend-services create consumer-bs \
--load-balancing-scheme=EXTERNAL_MANAGED \
--protocol=HTTPS \
--global
gcloud compute backend-services add-backend consumer-bs \
--network-endpoint-group=consumerpscneg \
--network-endpoint-group-region=asia-southeast1 \
--global
gcloud compute url-maps create consumer-url \
--default-service=consumer-backend-service \
--global
gcloud compute ssl-certificates create wwwglobal \
--certificate=fullchain.pem \
--private-key=private.pem \
--global
gcloud compute target-https-proxies create consumer-url-target-proxy \
--url-map=consumer-url \
--ssl-certificates=wwwglobal
gcloud compute forwarding-rules create consumer-url-forwarding-rule \
--load-balancing-scheme=EXTERNAL_MANAGED \
--network-tier=PREMIUM \
--address=httpspsclb \
--target-https-proxy=consumer-url-target-proxy \
--ports=443 \
--global
رکورد DNS مربوط به www01.yinghli.demo.altostrat.com را بهروزرسانی کنید و به آدرس IP عمومی External HTTPS Load Balancer اشاره کنید.
gcloud dns --project=$prodproject record-sets update www01.yinghli.demo.altostrat.com. --type="A" --zone="yinghli-demo" --rrdatas="34.102.178.214" --ttl="300"
۱۴. اعتبارسنجی
از طریق لپتاپ خود، با استفاده از curl به آدرس https://www01.yinghli.demo.altostrat.com دسترسی پیدا کنید.
curl -v https://www01.yinghli.demo.altostrat.com * Trying 34.102.178.214:443... * Connected to www01.yinghli.demo.altostrat.com (34.102.178.214) port 443 (#0) * ALPN: offers h2,http/1.1 * TLSv1.3 (OUT), TLS handshake, Client hello (1): * TLSv1.3 (IN), TLS handshake, Server hello (2): * TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8): * TLSv1.3 (IN), TLS handshake, Certificate (11): * TLSv1.3 (IN), TLS handshake, CERT verify (15): * TLSv1.3 (IN), TLS handshake, Finished (20): * TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1): * TLSv1.3 (OUT), TLS handshake, Finished (20): * SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384 * ALPN: server accepted h2 * Server certificate: * subject: CN=www01.yinghli.demo.altostrat.com * start date: Jun 4 10:36:43 2023 GMT * expire date: Sep 2 10:36:42 2023 GMT * subjectAltName: host "www01.yinghli.demo.altostrat.com" matched cert's "www01.yinghli.demo.altostrat.com" * issuer: C=US; O=Let's Encrypt; CN=R3 * SSL certificate verify ok. * using HTTP/2 * h2h3 [:method: GET] * h2h3 [:path: /] * h2h3 [:scheme: https] * h2h3 [:authority: www01.yinghli.demo.altostrat.com] * h2h3 [user-agent: curl/8.0.0] * h2h3 [accept: */*] * Using Stream ID: 1 (easy handle 0x149019a00) > GET / HTTP/2 > Host: www01.yinghli.demo.altostrat.com > user-agent: curl/8.0.0 > accept: */* > * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * TLSv1.3 (IN), TLS handshake, Newsession Ticket (4): * old SSL session ID is stale, removing < HTTP/2 200 < server: nginx/1.18.0 < date: Mon, 05 Jun 2023 02:48:43 GMT < content-type: text/html < content-length: 35 < last-modified: Sun, 04 Jun 2023 09:02:16 GMT < etag: "647c5318-23" < accept-ranges: bytes < via: 1.1 google, 1.1 google < alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000 < Page on www01 in asia-southeast1-b * Connection #0 to host www01.yinghli.demo.altostrat.com left intact
۱۵. مراحل پاکسازی
مراحل پاکسازی شبکه تولیدکنندگان
توجه: مراحل پاکسازی فقط پیکربندی مربوط به Load Balancer و PSC را نشان میدهد، VPC و Hybrid Connectivity شامل آن نمیشوند.
از یک پوسته ابری واحد در ترمینال، اجزای آزمایشگاه را حذف کنید
gcloud compute forwarding-rules delete consumer-url-forwarding-rule --global gcloud compute target-https-proxies delete consumer-url-target-proxy gcloud compute ssl-certificates delete wwwglobal --global gcloud compute url-maps delete consumer-url gcloud compute backend-services delete consumer-bs --global gcloud compute addresses delete httpspsclb --global gcloud beta compute network-endpoint-groups delete consumerpscneg --region=asia-southeast1 gcloud compute service-attachments delete ilbserviceattach --region=asia-southeast1 gcloud compute networks subnets delete psc-nat-subnet --region=asia-southeast1 gcloud compute forwarding-rules delete https-ilb-psc --region=asia-southeast1 gcloud compute addresses delete ilbaddress --region=asia-southeast1 gcloud compute target-https-proxies delete on-premise-httpsproxy --region=asia-southeast1 gcloud compute ssl-certificates delete www01 --region=asia-southeast1 gcloud compute url-maps delete on-premise-url --region=asia-southeast1 gcloud compute backend-services delete on-premise-service-backend --region=asia-southeast1 gcloud compute health-checks delete on-prem-service-hc --region=asia-southeast1 gcloud compute network-endpoint-groups delete on-prem-service-neg --zone=asia-southeast1-b gcloud compute networks subnets delete proxy-subnet-asia-southeast1 --region=asia-southeast1
۱۶. تبریک میگویم!
تبریک میگویم که آزمایشگاه کد را تمام کردی.
آنچه ما پوشش دادهایم
- متعادلکننده بار داخلی HTTPS با NEG ترکیبی و بررسی سلامت توزیعشده
- پیوست سرویس PSC با متعادلکننده بار داخلی HTTPS
- راهاندازی گروه نقطه پایانی شبکه PSC
- افشای PSC NEG با متعادلکننده بار خارجی HTTPS