Docker Network Ayarları Değişikliği

31 Eki

Docker sanallaştırma sistemi, varsayılan ayarlarda 172.17.0.0/12 ağlarını kullanır. Sistemde bu ağlardaki adresleri kullanan başka cihazlar (sunucu, bilgisayar vs.) varsa Docker ayarlarını değiştirebilirsiniz. Bu durumda, olası ağ çakışmalarını önlenebilir. Örneğin 172.21.122.23 adresinde çalışan bir varitabanı sunucusu varsa ve kendi bilgisayarınız bu sunucuya ulaşabildiği halde docker container erişemiyorsa, bu durumda çakışma olma ihtimali yüksektir.

Docker mevcut ağ ayarlarının görüntülenmesi

Docker üzerinde hangi ağların kullanıldığını öğrenmek için aşağıdaki komut kullanılır:

docker network list

Komut çıktısında NAME sütunu, kullanılan ağların adlarını gösterir.

NETWORK ID          NAME               DRIVER              SCOPE
24a38927e118        bridge             bridge              local
b92a38ed491b        elk_net            bridge              local
1d9237551d88        microservice       bridge              local
f57c6099ef24        host               host                local
dbb6fb4096c5        none               null                local

Kullanılan adres alanı (address space) hakkında bilgi almak için aşağıdaki komut kullanılır.

docker network inspect elk_net | grep Subnet
"Subnet": "172.19.0.0/16"

docker network inspect bridge | grep Subnet
"Subnet": "172.19.0.0/16"

Görüldüğü üzere Subnet ayarları tüm network’ler için 172.19.0.0/16 şeklindedir.

Docker mevcut ağ ayarlarının değiştirilmesi

Mevcut ağ ayarlarının değiştirilmesi için windows ve linux işletim sistemlerinde deamon.json dosyalarında düzenleme yapılması gerekmektedir.

Linux dosya konumu: /etc/docker/daemon.json

Windows dosya konumu: C:/Users/YourUserName/.docker/daemon.json

Adım-1

Dosyaya aşağıdaki komutların girilmesi

{
	"live-restore": true,
	"bip": "10.10.0.1/16",
	"default-address-pools": [{
		"base": "10.0.0.0/8",
		"size": 16
	}]
}

Adım-2

Tüm container’ların kaldırılması.

docker rm -f `docker ps -q -a`

Adım-3

Kullanılmayan Docker objelerinin silinmesi.

docker system prune
docker network prune

Adım-4

Docker’ın yeniden başlatılması.

Windows sistemde docker desktop yeniden başlatılır. Linux sistemlerde aşağıdaki komut çalıştırlabilir.

systemctl restart docker

Bu işlemlerin ardından adres alanı (address space) bilgilerine tekrar bakıldığında aşağıdaki gibi değiştiği görülür.

docker network inspect bridge | grep Subnet
"Subnet": "10.10.0.0/16"

Bu durumda network değişikliği tamamlanmış olacaktır. Artık 172’li ip çakışma durumları ortadan kalkacaktır.

Dotnet Core HttpClient Kullanımı

29 Eki

Dotnet core veya .Net Framework uygulamalarında bir Web servisine erişmek için HttpClient sınıfından bir nesne oluşturulur ve kullanılır. Buraya kadar her şey normal. İşlem bittikten sonra kullanılan bu nesne yok edilir. İşte bu durumda işler biraz karışmaya başlar.

HttiClinet using blok ile kullanımı

public class ToDoClient : IToDoClient
{
	public async Task<Todo> Get(int id)
	{
		using(var client = new HttpClient())
		{
			BaseAddress = new Uri(
				"https://jsonplaceholder.typicode.com");
		}
		
		return await client.GetFromAsync<ToDo>(
			$"/todos/{id}");
	}
}

HttpClient sınıfı, IDisposible interface uyguladığı için, using bloğu ile kullanılabilir. Using bloğunda oluşturulan nesneler, blok sonunda ortadan kaldırılır. Ancak nesnenin kullandığı soket hemen serbest bırakılmaz. Ağır yük altında kullanılabilir soket sayısı azalır hatta tükenebilir. Burada konu ile ilgili bir yazı bulunmaktadır.

Yeniden kullanılabilir HttpClient nesnesi

Bu durumun önüne geçmek için tek bir kez singleton olarak oluşturulan ve paylaşılan bir HttpClient nesnesi kullanılabilir.

public class ToDoClient : IToDoClient
{
   private readonly HttpClient client = new ()
	{
		 BaseAddress = new Uri(
			"https://jsonplaceholder.typicode.com");
	};

	public async Task<Todo> Get(int id)
	{		
		return await client.GetFromAsync<ToDo>(
			$"/todos/{id}");
	}
}

Bu çözüm ise, az sayıda kullanılan kısa ömürlü console uygulamaları için uygun olabilir. Ancak geliştiricilerin karşılaştığı diğer bir sorun, uzun süren işlemlerde paylaşılan bir HttpClient örneği kullanırken ortaya çıkar. HttpClient’in tekil veya statik bir nesne olarak başlatıldığı bir durumda, DNS ip değişiklikleri yapılırsa uygulama hata alır. Örneğin load balancer ile bir DNS birden fazla ip de bulunan sunuculara sırayla yönlendiriliyor olabilir.

builder.Services.AddSingleton<IToDoClient, ToDoClient>();

Bu arada ToDoClient Program.cs içerisinde singleton olarak tanımlanabilir. Eğer Transient veya Scoped olarak kullanılırsa her request sırasında yeniden nesne oluşturacaktır. Bu durumun önüne geçmek için HttpCleint nesnesi static olarak tanımlanabilir.

public class ToDoClient : IToDoClient
{
    private static readonly HttpClient client = new ()
	{
		 BaseAddress = new Uri(
			"https://jsonplaceholder.typicode.com");
	};

	public async Task<Todo> Get(int id)
	{		
		return await client.GetFromAsync<ToDo>(
			$"/todos/{id}");
	}
}

Ancak bu durumda BaseAddress ile tanımlanan DNS TTL süresi bittiğinde domain adı yeni bir ip adresini işaret eder. Ancak kod restart olmadan yeni ip adresini bilemez. Çünkü default HttpClient içerisinde bunu yakalayan bir mekanizma bulunmaz. Bu durumun yakalayabilmek için SockeHttpHandler kullanılabilir.

public class ToDoClient : IToDoClient
{
	private SocketsHttpHandler socketHandler = new()
	{
		PooledConnectionLifetime = TimeSpan.FromMinutes(5)
	};
	
    private static readonly HttpClient client = new (socketHandler)
	{
		 BaseAddress = new Uri(
			"https://jsonplaceholder.typicode.com");
	};

	public async Task<Todo> Get(int id)
	{		
		return await client.GetFromAsync<ToDo>(
			$"/todos/{id}");
	}
}

Ancak bu yöntem de en iyi çözüm yolu değildir. En iyi çözüm yolu  .NET Core 2.1 ile birlikte gelen IHttpClientFactory interface kullanmaktır.

IHttpClientFactory Kullanımı

Bu interface kullanmadan önce Program.cs içerisinde bir tanımlama yapılması gerekmektedir.

builder.Services.AddSingleton<IToDoClient, ToDoClient>();
builder.Services.AddHttpClient<IToDoClient, ToDoClient>(client =>
{
   client.BaseAddress = new Uri(
			"https://jsonplaceholder.typicode.com");
});

Bu düzenleme ile artık HttpClient aşağıdaki gibi kullanılabilir.

public class ToDoClient : IToDoClient
{
    private readonly HttpClient _httpClient;
	
	public ToDoClient(HttpClient httpClient)
	{
		_httpClient = httpClient;
	}
	
	public async Task<Todo> Get(int id)
	{		
		return await _httpClient.GetFromAsync<ToDo>(
			$"/todos/{id}");
	}
}

Bu durumda HttpClient nesnesi IHttpClientFactory tarafından yönetilmektedir. Çünkü ortak bir havuzdaki HttpMessageHandler nesneleri, birden çok HttpClient örneği tarafından yeniden kullanılabilen nesnelerdir. Bu sayede DNS sorunu çözülmektedir.

Named Client kullanımı

Servis binding sırasında AddHttpClient() metoduna bir isim vererk kullanmak mümkündür.

builder.Services.AddSingleton<IToDoClient, ToDoClient>();
builder.Services.AddHttpClient("TodoApi",client =>
{
   client.BaseAddress = new Uri(
			"https://jsonplaceholder.typicode.com");
});
public class ToDoClient : IToDoClient
{
    private readonly IHttpClientFactory _httpClientFactory;
	
	public ToDoClient(IHttpClientFactory httpClientFactory)
	{
		_httpClientFactory = httpClientFactory;
	}
	
	public async Task<Todo> Get(int id)
	{		
	    var client = _httpClientFactory.CreateClient("ToDoApi");
		
		return await client.GetFromAsync<ToDo>(
			$"/todos/{id}");
	}
}

Bu sayede doğrudan IHttpClientFactory interface nesneleri ile HttpClient request’leri en verimli şekilde gerçekleştirilebilmektedir.

Kaynaklar

  • https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests
  • https://www.aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/