Diagnosis dan perbaiki kegagalan DNS di kluster ACK yang disebabkan oleh masalah CoreDNS, jaringan, kebijakan, atau kernel.
Cara kerja resolusi DNS
Saat sebuah Pod aplikasi mengirim kueri DNS, kueri tersebut mengikuti alur berikut:
-
Pod mengirim kueri DNS ke alamat dalam
/etc/resolv.conf, yang biasanya merupakan IP layanan kube-dns. -
kube-dns meneruskan kueri tersebut ke Pod CoreDNS di namespace
kube-system. -
Untuk nama domain internal yang diakhiri dengan
.cluster.local, CoreDNS melakukan resolusi dari cache-nya tanpa menghubungi server upstream. -
Untuk nama domain eksternal, CoreDNS meneruskan kueri ke server DNS upstream yang ditentukan dalam konfigurasinya. Server upstream default adalah
100.100.2.136dan100.100.2.138, keduanya dideploy di virtual private cloud (VPC).
Dengan NodeLocal DNSCache, kueri terlebih dahulu menuju cache lokal (169.254.20.10) dan hanya menggunakan kube-dns sebagai fallback jika tidak terselesaikan.
Konsep utama
| Term | Description |
|---|---|
| Nama domain internal | Domain yang diakhiri dengan .cluster.local. CoreDNS melakukan resolusi dari cache, bukan dari server upstream. |
| Nama domain eksternal | Domain yang tidak diakhiri dengan .cluster.local. CoreDNS meneruskan kueri ke server DNS upstream. |
| Pod aplikasi | Pod apa pun yang bukan komponen sistem. |
| Layanan kube-dns | Layanan Kubernetes yang mengarahkan trafik DNS ke Pod CoreDNS. IP-nya merupakan nameserver default untuk Pod aplikasi. |
| NodeLocal DNSCache | DaemonSet yang menjalankan cache DNS lokal di setiap node. Saat diaktifkan, Pod melakukan kueri ke cache lokal (169.254.20.10) alih-alih ke kube-dns. |
| Server DNS upstream | Server DNS yang dihubungi CoreDNS untuk domain eksternal. Default-nya adalah 100.100.2.136 dan 100.100.2.138. |
Langkah 1: Identifikasi pesan error Anda
Cocokkan pesan error Anda untuk menentukan kategori kegagalan yang paling mungkin.
| Client | Pesan error | Kemungkinan penyebab |
|---|---|---|
| ping | ping: xxx.yyy.zzz: Name or service not known |
Domain tidak ada atau server DNS tidak dapat dijangkau. Latensi >5 detik mengindikasikan server tidak dapat dijangkau. |
| curl | curl: (6) Could not resolve host: xxx.yyy.zzz |
Sama seperti di atas. |
| PHP HTTP client | php_network_getaddresses: getaddrinfo failed: Name or service not known in xxx.php on line yyy |
Sama seperti di atas. |
| Golang HTTP client | dial tcp: lookup xxx.yyy.zzz on 100.100.2.136:53: no such host |
Domain tidak ada. |
| dig | ;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: xxxxx |
Domain tidak ada. |
| Golang HTTP client | dial tcp: lookup xxx.yyy.zzz on 100.100.2.139:53: read udp 192.168.0.100:42922->100.100.2.139:53: i/o timeout |
Server DNS tidak dapat dijangkau. |
| dig | ;; connection timed out; no servers could be reached |
Server DNS tidak dapat dijangkau. |
-
Domain does not exist → Periksa apakah nama domain tersebut sudah benar. Jika hanya domain eksternal yang gagal, lihat Nama domain eksternal tidak dapat diselesaikan.
-
DNS server unreachable → Lanjutkan ke Langkah 2.
Langkah 2: Periksa kebijakan DNS dan alamat server
Verifikasi bahwa Pod menggunakan CoreDNS sebagai server DNS-nya.
Ambil kebijakan dan konfigurasi DNS:
# Lihat kebijakan DNS Pod
kubectl get pod <pod-name> -o yaml
# Masuk ke Pod dan periksa konfigurasi DNS
kubectl exec -it <pod-name> -- cat /etc/resolv.conf
Periksa field dnsPolicy dan entri nameserver dalam /etc/resolv.conf.
dnsPolicy |
Perilaku |
|---|---|
ClusterFirst |
Default. Pod menggunakan IP layanan kube-dns sebagai server DNS. |
ClusterFirstWithHostNet |
Sama seperti ClusterFirst untuk Pod dengan jaringan host. |
Default |
Pod mewarisi pengaturan DNS dari node Elastic Compute Service (ECS). Gunakan hanya saat Pod tidak perlu menyelesaikan nama internal kluster. |
None |
DNS dikonfigurasi sepenuhnya melalui dnsConfig. NodeLocal DNSCache menggunakan ini untuk menyisipkan 169.254.20.10 dan IP kube-dns sebagai nameserver. |
Jika Pod tidak menggunakan CoreDNS (nameserver bukan IP layanan kube-dns), Pod mungkin kelebihan beban atau tabel conntrack penuh. Lihat Client kelebihan beban dan Tabel conntrack penuh.
Jika Pod menggunakan NodeLocal DNSCache (nameserver adalah 169.254.20.10), lihat NodeLocal DNSCache tidak berfungsi dan Nama Alibaba Cloud DNS PrivateZone tidak dapat diselesaikan.
Jika Pod menggunakan CoreDNS, lanjutkan ke Langkah 3.
Langkah 3: Periksa kesehatan Pod CoreDNS
Periksa Pod CoreDNS:
# Lihat status dan penempatan Pod CoreDNS
kubectl -n kube-system get pod -o wide -l k8s-app=kube-dns
Output yang diharapkan:
NAME READY STATUS RESTARTS AGE IP NODE
coredns-xxxxxxxxx-xxxxx 1/1 Running 0 25h 172.20.6.53 cn-hangzhou.192.168.0.198
# Lihat penggunaan CPU dan memori secara real-time
kubectl -n kube-system top pod -l k8s-app=kube-dns
Output yang diharapkan:
NAME CPU(cores) MEMORY(bytes)
coredns-xxxxxxxxx-xxxxx 3m 18Mi
-
Pods not in Running state → Jalankan
kubectl -n kube-system describe pod <CoreDNS-pod-name>untuk mengidentifikasi penyebabnya. Lihat Pod CoreDNS tidak berjalan normal. -
CPU or memory near the limit → Lihat Pod CoreDNS kelebihan beban.
-
CPU usage uneven across pods → Lihat Kueri DNS tidak terdistribusi merata.
Langkah 4: Periksa log operasional CoreDNS
kubectl -n kube-system logs -f --tail=500 --timestamps <coredns-pod-name>
| Flag | Description |
|---|---|
-f |
Alirkan keluaran log. |
--tail=500 |
Menampilkan 500 baris terakhir. |
--timestamps |
Menyertakan timestamp pada setiap baris log. |
Cari pola error yang sesuai dengan isu-isu yang diketahui. Untuk log tingkat kueri DNS, aktifkan terlebih dahulu plugin log CoreDNS. Lihat Konfigurasi resolusi DNS.
Dengan plugin log diaktifkan, setiap kueri yang terselesaikan menghasilkan entri seperti:
[INFO] 172.20.2.25:44525 - 36259 "A IN redis-master.default.svc.cluster.local. udp 56 false 512" NOERROR qr,aa,rd 110 0.000116946s
Kode respons umum:
| Kode respons | Makna | Tindakan |
|---|---|---|
NOERROR |
Berhasil diselesaikan. | Tidak perlu tindakan. |
NXDOMAIN |
Domain tidak ada di server upstream. | Periksa apakah nama domain mencakup sufiks pencarian yang tidak dapat diselesaikan. |
SERVFAIL |
Server DNS upstream mengembalikan error. | Periksa konektivitas CoreDNS ke server upstream. |
REFUSED |
Server upstream menolak kueri tersebut. | Periksa konfigurasi Corefile CoreDNS dan /etc/resolv.conf pada node. |
Kode respons DNS didefinisikan dalam RFC 1035.
Langkah 5: Reproduksi error dan isolasi penyebabnya
Jika error terjadi secara konsisten:
-
Periksa log kueri DNS untuk kode respons error. Lihat Nama domain eksternal tidak dapat diselesaikan.
-
Uji konektivitas jaringan antara Pod aplikasi dan CoreDNS. Lihat Uji konektivitas jaringan antara Pod aplikasi dan CoreDNS.
-
Diagnosis jaringan kontainer. Lihat Diagnosis jaringan kontainer.
Jika error terjadi secara intermiten:
Lakukan pengambilan paket untuk mengumpulkan bukti. Lihat Pengambilan paket.
Jika belum terselesaikan, atau kirim tiket.
Metode diagnostik
Uji konektivitas jaringan antara Pod aplikasi dan CoreDNS
Masuk ke namespace jaringan Pod aplikasi menggunakan salah satu metode berikut:
-
Metode 1 (disarankan): Jalankan
kubectl exec -it <pod-name> -- bashuntuk masuk ke Pod. -
Metode 2: Masuk ke node, cari ID proses dengan
ps aux | grep <application-process-name>, lalu masuk ke namespace jaringan dengannsenter -t <pid> -n bash. -
Metode 3 (untuk Pod yang sering restart):
-
Masuk ke node.
-
Jalankan
docker ps -a | grep <application-container-name>untuk mencari ID kontainer sandbox (nama dimulai dengank8s_POD_). -
Jalankan
docker inspect <sandboxed-container-ID> | grep netnsuntuk mencari path namespace jaringan di/var/run/docker/netns/xxxx. -
Jalankan
nsenter -n<netns-path> bash</netns-path>untuk masuk ke namespace tersebut. > Note: Jangan tambahkan spasi antara-ndan<netns-path>.
-
Dari namespace jaringan Pod, uji konektivitas:
# Uji konektivitas ke layanan kube-dns
dig <domain> @<kube-dns-svc-ip>
# Uji konektivitas Internet Control Message Protocol (ICMP) ke Pod CoreDNS
ping <coredns-pod-ip>
# Uji kueri DNS langsung ke Pod CoreDNS
dig <domain> @<coredns-pod-ip>
Ganti <kube-dns-svc-ip> dengan IP layanan kube-dns di namespace kube-system, dan <coredns-pod-ip> dengan IP Pod CoreDNS.
| Gejala | Kemungkinan penyebab | Langkah selanjutnya |
|---|---|---|
| Tidak dapat menjangkau layanan kube-dns | Node kelebihan beban, kube-proxy mati, atau security group memblokir port User Datagram Protocol (UDP) 53 | Verifikasi bahwa aturan security group mengizinkan trafik UDP port 53. Jika sudah, kirim tiket. |
| Tidak dapat menjangkau Pod CoreDNS (ICMP) | Error jaringan kontainer atau security group memblokir ICMP | Diagnosis jaringan kontainer. |
| Tidak dapat menjangkau Pod CoreDNS (DNS) | Node kelebihan beban atau security group memblokir UDP port 53 | Verifikasi bahwa aturan security group mengizinkan UDP port 53. Jika sudah, kirim tiket. |
Uji konektivitas jaringan CoreDNS
-
Masuk ke node tempat Pod CoreDNS berjalan.
-
Jalankan
ps aux | grep corednsuntuk mendapatkan ID proses CoreDNS. -
Jalankan
nsenter -t <pid> -n bashuntuk masuk ke namespace jaringan CoreDNS. -
Uji konektivitas:
# Uji konektivitas ke server API Kubernetes telnet <apiserver_clusterip> 6443 # apiserver_clusterip adalah ClusterIP layanan kubernetes di namespace default. # Uji konektivitas ke server DNS upstream dig <domain> @100.100.2.136 dig <domain> @100.100.2.138
| Gejala | Kemungkinan penyebab | Langkah selanjutnya |
|---|---|---|
| Tidak dapat menjangkau server API Kubernetes | Error server API, node kelebihan beban, atau kube-proxy mati | kirim tiketKirim tiketKirim tiketKirim tiketKirim tiketKirim tiketKirim tiketKirim tiketKirim tiketKirim tiket. |
| Tidak dapat menjangkau server DNS upstream | Node kelebihan beban, CoreDNS salah konfigurasi, atau error routing Express Connect | kirim tiketKirim tiketKirim tiketKirim tiketKirim tiketKirim tiketKirim tiketKirim tiketKirim tiketKirim tiket. |
Diagnosis jaringan kontainer
-
Masuk ke Konsol ACKKonsol ACK.
-
Pada halaman Clusters, klik nama kluster Anda atau klik Details di kolom Actions.
-
Di panel navigasi kiri, pilih Operations > Cluster Check.
-
Pada halaman Container Intelligence Service, pilih Cluster Check > Diagnosis.
-
Pada halaman Diagnosis, klik tab Network Diagnosis.
-
Atur Source address ke IP Pod aplikasi, Destination address ke IP layanan kube-dns, dan Port tujuan ke
53. Pilih Enable packet tracing dan I know and agree, lalu klik Create diagnosis. -
Di daftar diagnosis, klik Diagnosis details untuk catatan Anda.
Hasilnya menampilkan Diagnosis result, Packet paths, dan Semua jalur yang mungkin, beserta penyebab error yang teridentifikasi. Lihat Gunakan fitur diagnostik kluster untuk mengatasi masalah kluster.
Pengambilan paket
Gunakan pengambilan paket saat error bersifat intermiten dan sulit direproduksi.
-
Masuk ke node tempat Pod aplikasi dan Pod CoreDNS berjalan.
-
Ambil trafik DNS pada setiap instans ECS:
tcpdump -i any port 53 -C 20 -W 200 -w /tmp/client_dns.pcapIni mengambil semua trafik pada port 53, bergilir hingga maksimal 200 file masing-masing 20 MB.
-
Reproduksi error dan analisis paket dari jendela waktu kegagalan. Periksa log aplikasi untuk timestamp yang tepat.
Pengambilan paket memiliki dampak layanan yang dapat diabaikan—hanya sedikit peningkatan pada utilisasi CPU dan I/O disk.
Isu-isu yang diketahui
Periksa isu-isu spesifik lingkungan berikut sebelum melakukan investigasi lebih dalam.
| Isu | Lingkungan yang terpengaruh | Identifikasi cepat |
|---|---|---|
| Kueri rekaman A dan AAAA konkuren | Semua (terutama image berbasis Alpine dan aplikasi PHP) | Kegagalan intermiten; pengambilan paket menunjukkan kueri A/AAAA simultan pada port yang sama |
| Konflik port sumber UDP IPVS | kube-proxy dalam mode IP Virtual Server (IPVS); CentOS atau Alibaba Cloud Linux 2 dengan kernel sebelum 4.19.91-25.1.al7.x86_64 |
Kegagalan berlangsung sekitar 5 menit selama scaling node atau CoreDNS |
| Tabel conntrack penuh | Node dengan trafik tinggi | dmesg -H menunjukkan conntrack full; kegagalan terjadi saat jam sibuk |
| Alibaba Cloud DNS PrivateZone dengan NodeLocal DNSCache | Kluster yang menggunakan NodeLocal DNSCache dan DNS PrivateZone | Nama PrivateZone atau domain vpc-proxy gagal diselesaikan atau diselesaikan ke alamat yang salah |
| Bug plugin autopath | Kluster yang membuat kontainer dengan frekuensi tinggi | Nama eksternal kadang gagal atau diselesaikan ke IP yang salah; nama internal biasanya berhasil, kecuali di kluster yang membuat kontainer dengan frekuensi tinggi, di mana nama layanan internal juga bisa diselesaikan ke IP yang salah |
| Nama DNS PrivateZone dan vpc-proxy | Kluster tempat nama domain internal dan eksternal gagal | Error resolusi hanya terjadi pada nama domain yang ditambahkan ke Alibaba Cloud DNS PrivateZone dan nama domain yang mengandung vpc-proxy |
FAQ
Nama domain eksternal tidak dapat diselesaikan
Periksa log kueri CoreDNS untuk kode respons. Aktifkan plugin log jika belum diaktifkan (lihat Konfigurasi resolusi DNS), lalu cari domain yang gagal. NXDOMAIN berarti domain tidak ada di upstream—sering kali karena sufiks pencarian ditambahkan, sehingga menghasilkan FQDN yang tidak valid. SERVFAIL atau REFUSED berarti server upstream bermasalah; periksa konfigurasi CoreDNS dan konektivitas ke 100.100.2.136 dan 100.100.2.138.
Nama domain layanan headless tidak dapat diselesaikan
Pada CoreDNS sebelum versi 1.7.0, fluktuasi jaringan server API dapat menyebabkan CoreDNS keluar, sehingga pembaruan catatan layanan headless terhenti. Perbarui ke versi 1.7.0 atau lebih baru. Lihat \[Pembaruan Komponen\] Perbarui CoreDNS.
Nama domain Pod StatefulSet tidak dapat diselesaikan
Templat Pod StatefulSet harus mengatur serviceName ke nama layanan headless. Tanpa ini, nama DNS per-Pod (misalnya, pod.headless-svc.ns.svc.cluster.local) tidak dapat diselesaikan, meskipun nama tingkat layanan (misalnya, headless-svc.ns.svc.cluster.local) berfungsi. Atur serviceName dalam spesifikasi StatefulSet.
Kueri DNS diblokir oleh aturan security group atau ACL jaringan
Aturan security group atau daftar kontrol akses jaringan (ACL) memblokir port UDP 53, menyebabkan kegagalan DNS pada node yang terpengaruh. Izinkan trafik UDP port 53 arah masuk dan keluar.
Error konektivitas jaringan kontainer menyebabkan kegagalan DNS
Error jaringan kontainer memblokir port UDP 53. Gunakan fitur Diagnostik Jaringan untuk mengidentifikasi jalur yang rusak dan akar penyebabnya.
Pod CoreDNS kelebihan beban
Saat volume kueri melebihi kapasitas replika CoreDNS, latensi meningkat dan kegagalan terjadi. Periksa apakah penggunaan CPU dan memori mendekati batas (kubectl -n kube-system top pod -l k8s-app=kube-dns).
Dua solusi:
-
Deploy NodeLocal DNSCache untuk menyerap kueri secara lokal dan mengurangi beban pada CoreDNS. Lihat Konfigurasi NodeLocal DNSCache.
-
Scale out replika CoreDNS agar utilisasi CPU puncak per Pod tetap jauh di bawah CPU yang tersedia pada node.
Kueri DNS tidak terdistribusi merata di antara Pod CoreDNS
Penjadwalan Pod yang tidak seimbang atau pengaturan sessionAffinity pada kube-dns dapat menyebabkan distribusi kueri tidak merata. Gejala: utilisasi CPU yang berbeda nyata di antara Pod CoreDNS.
Dua solusi:
-
Scale out Pod CoreDNS dan sebarkan di node yang berbeda.
-
Hapus pengaturan
sessionAffinitydari layanan kube-dns. Lihat Konfigurasi layanan kube-dns.
Pod CoreDNS tidak berjalan normal
YAML atau ConfigMap yang salah konfigurasi dapat mencegah CoreDNS dimulai atau menyebabkan crash. Gejala: Pod tidak dalam status Running, jumlah restart meningkat, atau error di log.
Periksa log CoreDNS untuk error umum berikut:
| Error | Penyebab | Perbaikan |
|---|---|---|
/etc/coredns/Corefile:4 - Error during parsing: Unknown directive 'ready' |
ConfigMap CoreDNS berisi plugin yang tidak didukung oleh versi saat ini. | Hapus plugin yang tidak didukung (misalnya, ready) dari ConfigMap di namespace kube-system. Ulangi untuk plugin lain dalam error tersebut. |
Failed to watch *v1.Pod: ... connect: connection refused |
Koneksi ke server API terputus saat log dihasilkan. | Jika tidak ada kegagalan DNS, ini bukan akar penyebabnya. Jika ada, uji konektivitas CoreDNS. Lihat Uji konektivitas jaringan CoreDNS. |
[ERROR] plugin/errors: 2 www.aliyun.com. A: read udp ...->100.100.2.136:53: i/o timeout |
CoreDNS tidak dapat menjangkau server DNS upstream. | Uji konektivitas dari Pod CoreDNS ke 100.100.2.136 dan 100.100.2.138. |
Resolusi DNS gagal karena client kelebihan beban
Saat instans ECS sepenuhnya dimuat, paket UDP mungkin terbuang sebelum mencapai CoreDNS. Cari laju Pengiriman ulang NIC (network interface controller) yang abnormal dan utilisasi CPU tinggi dalam data pemantauan.
Dua opsi:
-
Kirim tiketKirim tiketKirim tiketKirim tiketKirim tiketKirim tiketKirim tiketKirim tiketKirim tiketKirim tiket untuk investigasi lebih lanjut.
-
Deploy NodeLocal DNSCache untuk mengurangi trafik DNS antar-node. Lihat Konfigurasi NodeLocal DNSCache.
Tabel conntrack penuh
Saat tabel conntrack penuh, koneksi UDP dan TCP baru akan terbuang. Ini biasanya menyebabkan kegagalan DNS saat jam sibuk yang pulih di luar jam sibuk. Untuk mengonfirmasi, jalankan dmesg -H pada node yang terpengaruh dan cari conntrack full selama jendela kegagalan.
Tingkatkan jumlah maksimum entri dalam tabel conntrack. Lihat Bagaimana cara meningkatkan jumlah maksimum koneksi yang dilacak dalam tabel conntrack kernel Linux?
Plugin autopath tidak berfungsi normal
Cacat plugin autopath yang diketahui menyebabkan kegagalan resolusi sesekali atau IP yang salah untuk domain eksternal. Domain internal diselesaikan dengan benar. Masalah ini memburuk di kluster dengan tingkat pembuatan kontainer tinggi.
Nonaktifkan plugin autopath:
-
Edit ConfigMap CoreDNS dengan
kubectl -n kube-system edit configmap coredns. -
Hapus baris
autopath @kubernetes. Simpan dan keluar. -
Verifikasi konfigurasi yang dimuat dengan memeriksa log CoreDNS untuk
reload.
Resolusi DNS gagal karena kueri rekaman A dan AAAA konkuren
Beberapa distribusi Linux mengirim kueri A dan AAAA secara simultan melalui port yang sama, memicu konflik conntrack yang mengakibatkan paket UDP terbuang.
Gejala: kegagalan resolusi intermiten; pengambilan paket menunjukkan kueri A dan AAAA simultan dari port sumber yang sama.
Solusi tergantung pada basis image Anda:
-
CentOS atau Ubuntu: Tambahkan
options timeout:2 attempts:3 rotate single-request-reopenke konfigurasi resolver DNS. -
Alpine Linux: Ganti image berbasis Alpine dengan image berbasis OS lain. Lihat Catatan Alpine.
-
PHP dengan cURL: Tambahkan
CURL_IPRESOLVE_V4untuk memaksa resolusi IPv4 saja. Lihat Fungsi cURL. -
Semua lingkungan: Deploy NodeLocal DNSCache, yang mengurangi kondisi race tersebut. Lihat Konfigurasi NodeLocal DNSCache.
Resolusi DNS gagal karena error IPVS
Dalam mode IPVS dengan CentOS atau Alibaba Cloud Linux 2 (kernel sebelum 4.19.91-25.1.al7.x86_64), penghapusan Pod backend UDP menyebabkan konflik port sumber yang mengakibatkan paket terbuang. Kegagalan DNS berlangsung ~5 menit selama event scaling node atau CoreDNS.
Dua solusi:
-
Deploy NodeLocal DNSCache untuk melewati jalur IPVS untuk kueri DNS. Lihat Konfigurasi NodeLocal DNSCache.
-
Persingkat timeout sesi UDP dalam mode IPVS. Lihat Ubah periode timeout UDP dalam mode IPVS.
NodeLocal DNSCache tidak berfungsi
Kueri DNS melewati NodeLocal DNSCache saat salah satu kondisi berikut berlaku:
-
dnsConfigtidak disisipkan ke Pod aplikasi, sehingga mereka masih mengarah ke IP layanan kube-dns. -
Pod menggunakan image berbasis Alpine Linux, yang melakukan kueri ke semua nameserver secara konkuren, termasuk langsung ke CoreDNS.
Untuk kasus pertama, aktifkan injeksi otomatis dnsConfig. Lihat Konfigurasi NodeLocal DNSCache. Untuk image Alpine, gunakan image yang dibangun di atas OS lain. Lihat Catatan Alpine.
Nama Alibaba Cloud DNS PrivateZone tidak dapat diselesaikan
Alibaba Cloud DNS PrivateZone memerlukan UDP, bukan TCP. Dengan NodeLocal DNSCache, domain PrivateZone, titik akhir API vpc-proxy, atau nama domain lain mungkin gagal diselesaikan atau diselesaikan ke IP yang salah.
Tambahkan prefer_udp ke konfigurasi CoreDNS untuk memaksa UDP untuk kueri upstream. Lihat Konfigurasi CoreDNS.