Kubernetes API Server Nedir? Nasıl Haberleşilir?
Kubernetes API Server, Kubernetes cluster'ındaki tüm etkileşimlerin yönetildiği ve kontrol edildiği merkezi bir bileşendir. Kubernetes API Server, Kubernetes cluster'ına istemciler tarafından yapılan istekleri alır, işler ve yanıtlar.
Bir önceki yazımızda container'lar içinden, o container'ların içinde çalıştığı Pod metadata verilerine nasıl erişebileceğini görmüştük. Bu yazımızda ise, tüm cluster içindeki herhangi bir Kubernetes nesnesinin bilgilerine nasıl erişebileceğimizi göreceğiz.
API Server, Kubernetes cluster için bir dışa açık API server görevi görür. Bu API üzerinden Kubernetes kaynaklarına (Pod'lar, Deployment'lar, Service'ler, ConfigMap'ler vb.) erişilebilir, oluşturulabilir, güncellenebilir ve silinebilir. Ayrıca, eventler, loglar ve diğer önemli bilgiler gibi bilgilere de API Server üzerinden erişilebilir.
Kubernetes Server API ile iletişime geçebilmek için iki yöntemimiz bulunuyor;
- kubectl proxy komutu ile local makine üzerindeki bir proxy server üzerinden
- kubernetes service adresi ile herhangi bir container içerisinden
Bu yöntemlerin her birine detaylıca bakalım.
1. Kubectl Proxy İle Proxy Server Üzerinden Server API Erişimi
kubectl aracının yüklü olduğu local makineniz üzerinden Server API ile iletişime geçmek oldukça kolaydır. Bunun için ilk olarak Server API'ın nerede olduğunu öğrenmemiz gerekir.
Server API'ın nerede olduğunu öğrenmek için kubectl cluster-info
komutunu kullanabiliriz.
$ kubectl cluster-info
Kubernetes master is running at https://192.168.99.100:8443
Kubernetes Server API'ın nerede olduğunu öğrendikten sonra herhangi bir authentication işlemi gerekmeden iletişime geçebilmek için proxy server kullanmalıyız. Aksi halde API server'a attığınız işlemler Unauthorized
hatası verecektir.
$ curl https://192.168.99.100:8443 -k
Unauthorized
kubectl proxy
komutu, local makinenizde HTTP bağlantılarını kabul eden ve authentication işlemini kendi halleden bir proxy sunucusu çalıştırır. Böylece her istekte authentication token iletmeniz gerekmez. Ayrıca, man-in-the-middle ataklarını engellemek için her istekte sunucunun sertifikasını doğrular.
Proxy server'ı aktif etmek için kubectl proxy
komutu çalıştırmak yeterlidir. Bu komut, API server ile konuşabilmeniz için 8001 portunda bir proxy server çalıştırır.
$ kubectl proxy
Starting to serve on 127.0.0.1:8001
Artık attığınız tüm API istekleri çok basit ve zahmetsiz bir şekilde size yanıt dönecektir.
$ curl localhost:8001
{
"paths": [
"/api",
"/api/v1",
...
$ curl http://localhost:8001/apis/batch/v1/namespaces/default/jobs/my-job
{
"kind": "Job",
"apiVersion": "batch/v1",
"metadata": {
"name": "my-job",
"namespace": "default",
...
kubectl get ...... -o json
komutu ile aldığınız sonucun aynısıdır.2. Kubernetes Service Adresi ile Herhangi Bir Container İçerisinden Server API Erişimi
Proxy server sayesinde Server API ile nasıl konuşabileceğimizi önceki başlıkta gördük. Fakat kubectl aracı, özel bir gayret göstermediyseniz neredeyse hiçbir container içinde yer almaz. Bu durumda proxy açamayacağımız için API server ile konuşabilmek için şu üç şeye ihtiyacımız olacak;
- API server adresini bulmak
- API server'ın sertifikasını doğrulamak
- Authentication işlemi
Bu üç aşamayı sırasıyla halledelim.
2.1. API Server Adresini Bulmak
İlk ihtiyaç duyduğumuz şey, konuşacağımız API Server'ın IP adres ve port bilgisini elde etmektir. Bunun için kullanabileceğimiz ilk yöntem kubectl services
komutunu çalıştırmaktır.
$ kubectl get svc
NAME CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes 10.0.0.1 <none> 443/TCP 46d
kubernetes
isimli service, Kubernetes tarafından default
namespace altında otomatik olarak expose edilir ve API server'a bağlanır.
API server'ı bulmanın diğer bir yolu ise container içinden environment variable'lar içinde yer alan KUBERNETES_SERVICE_HOST
ve KUBERNETES_SERVICE_PORT
değerlerini kontrol etmektir.
$ env | grep KUBERNETES_SERVICE
KUBERNETES_SERVICE_PORT=443
KUBERNETES_SERVICE_HOST=10.0.0.1
KUBERNETES_SERVICE_PORT_HTTPS=443
Kubernetes cluster içinde yer alan tüm container'lara, Service adres ve port bilgilerinin env olarak eklendiğini Service yazımızda belirtmiştik.
Son olarak ise her Service'in bir DNS girdisi olduğu için direkt service ismiyle containerlar içinden erişebilirsiniz. Örneğin burada https://kubernetes
adresi, Server API adresidir.
2.2. API Server'ın Sertifikasını Doğrulamak
Şimdi yukarıdaki üç yöntemden herhangi birisini kullanarak Server API adresini elde edip container içinden istek attığınızda CA SSL doğrulama hatası aldığınızı göreceksiniz.
$ curl https://kubernetes
curl: (60) SSL certificate problem: unable to get local issuer certificate
...
If you'd like to turn off curl's verification of the certificate, use
the -k (or --insecure) option.
Bu sorunu çözmenin en basit yolu --insecure
veya -k
parametresi ile bu sertifika doğrulama aşamasını disable etmenizdir. Fakat bunu önermiyoruz.
Bir önceki Secret yazımızda, Secret'ları listelediğinizde default-token-xyz
ismiyle otomatik oluşturulan bir Secret kaydı görmüştünüz.
default-token-xyz
isimli secret, her container'ın /var/run/secrets/kubernetes.io/serviceaccount/
dizinine otomatik olarak mount edilir ve içinde ca.crt
isimli Certificate Authority (CA)'nın sertifikasını barındırır.
$ ls /var/run/secrets/kubernetes.io/serviceaccount/
ca.crt namespace token
Bu sertifikayı --cacert
parametresi ile belirterek sertifika doğrulama aşamsını kolaylıkla geçebilirsiniz.
curl --cacert /var/run/secrets/kubernetes.io/serviceaccount/ca.crt https://kubernetes
Her isteğe bu parametreyi eklemek yerine CURL_CA_BUNDLE
isimli environment variable ekleyerek bu parametreyi tüm isteklere otomatik ekletebilirsiniz.
export CURL_CA_BUNDLE=/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
curl https://kubernetes
2.3. Authentication İşlemi
Sertifika doğrulamasını da yaptıktan sonra attığımız isteklerin Unauthorized
döndüğünü görüyorsunuz.
$ curl https://kubernetes
Unauthorized
Server API ile authentication işlemini gerçekleştirebilmek için, yine default secret olan default-token-xyz
ile birlikte /var/run/secrets/kubernetes.io/serviceaccount/
dizininde gelen token
isimli dosyayı kullanacağız.
Baerar token değerini içeren bu dosyanın içeriğini ilk olarak TOKEN
isimli environment variable'a atıyoruz.
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
Ardından bu baerar token'ı isteğimizin header'ına koyarak istek attığımızda Server API'ın başarılı sonuç döndüğünü görebilirsiniz.
$ curl -H "Authorization: Bearer $TOKEN" https://kubernetes
{
"paths": [
"/api",
"/api/v1",
"/apis",
"/apis/apps",
"/apis/apps/v1beta1",
"/apis/authorization.k8s.io",
...
"/ui/",
"/version"
]
}
2.4. Namespace'ın Otomatik Tanımlanması
Bu aşama opsiyoneldir ve Pod'un içinde çalıştığı namespace'i otomatik tanımlayarak Server API'ya gönderdiği isteklerin kolaylaştırılmasını sağlar.
Default secret olan default-token-xyz
ile birlikte /var/run/secrets/kubernetes.io/serviceaccount/
dizininde gelen namespace
isimli dosya, pod'un hangi cluster altında çalıştığı bilgisini tutar.
Bu namespace dosya içerisindeki namespace bilgisini environment variable olarak ayarlayarak isteklerimizde kullanabiliriz.
NS=$(cat /var/run/secrets/kubernetes.io/serviceaccount/namespace)
curl -H "Authorization: Bearer $TOKEN" https://kubernetes/api/v1/namespaces/$NS/pods
2.5. Özet
Tüm adımları sıralar ve akışı görselleştirirsek aşağıdaki şemayı elde ederiz.
- Uygulama, API server sertifikasının, ca.crt dosyasında bulunan CA tarafından imzalanıp imzalanmadığını doğrular.
- Uygulama, token dosyasından baerar token ile Authorization başlığını göndererek kendi kimliğini doğrular.
- Pod'un kendi namespace'i içindeki API nesneleri üzerinde CRUD işlemleri gerçekleştirirken namespace bilgisini API sunucusuna iletmek için namespace dosyasını kullanır.
Sıradaki yazı ile eğitim serisine devam edebilirsiniz.