{"id":31131,"date":"2023-02-08T15:18:36","date_gmt":"2023-02-08T14:18:36","guid":{"rendered":"https:\/\/nearshore-it.eu\/artykuly\/jak-postawic-serwer-tcp-na-azure\/"},"modified":"2024-11-07T14:15:43","modified_gmt":"2024-11-07T13:15:43","slug":"jak-postawic-serwer-tcp-na-azure","status":"publish","type":"post","link":"https:\/\/nearshore-it.eu\/pl\/artykuly\/jak-postawic-serwer-tcp-na-azure\/","title":{"rendered":"Jak postawi\u0107 serwer TCP (Transmission Control Protocol) na platformie Azure \u2013 krok po kroku"},"content":{"rendered":"\n<div class=\"table-of-contents\">\n    <p class=\"title\">Przejd\u017a do:<\/p>\n    <ol>\n                    <li><a href=\"#Serwer-TCP-na-platformie-Azure-\u2013-ale-po-co?\">1.  Serwer TCP na\u00a0platformie Azure \u2013 ale\u00a0po\u00a0co?<\/a><\/li>\n                    <li><a href=\"#Komunikacja-po-TCP-\u2013-jakie-s\u0105-opcje?\">2.  Komunikacja po TCP \u2013 jakie s\u0105 opcje? <\/a><\/li>\n                    <li><a href=\"#Konfigurujemy-Azure-Container-Instances\">3.  Konfigurujemy Azure Container Instances <\/a><\/li>\n                    <li><a href=\"#Czas-na-testy\">4.  Testy<\/a><\/li>\n                    <li><a href=\"#Problem-zmiany-adresu-IP-po-prze\u0142adowaniu\u2026\">5.  Problem zmiany adresu IP po prze\u0142adowaniu&#8230;   <\/a><\/li>\n                    <li><a href=\"#Container-Apps-z-TCP-jako-kolejny-etap-ewolucji\">6.  Container Apps z TCP jako kolejny etap ewolucji <\/a><\/li>\n                    <li><a href=\"#Podsumowanie\">7.  Podsumowanie<\/a><\/li>\n            <\/ol>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"Serwer-TCP-na-platformie-Azure-\u2013-ale-po-co?\">Serwer TCP (Transmission Control Protocol) na platformie Azure \u2013 ale po co?<\/h2>\n\n\n\n<p>W naszym projekcie, pracuj\u0105c nad rozwi\u0105zaniem pozwalaj\u0105cym systemom POS (ang. point of sale) na obs\u0142ugiwanie p\u0142atno\u015bci, musieli\u015bmy <strong>zintegrowa\u0107 je z systemem obs\u0142uguj\u0105cym komunikacj\u0119 z terminalami p\u0142atniczymi<\/strong>. Wi\u0105za\u0142o si\u0119 to z posiadaniem fizycznego urz\u0105dzenia, w tym przypadku terminala, do cel\u00f3w testowych. Pracuj\u0105c w trybie zdalnym, z zespo\u0142em rozproszonym po kilku miastach w Polsce, niemo\u017cliwe by\u0142o wsp\u00f3\u0142dzielenie jednego takiego urz\u0105dzenia. Zdecydowali\u015bmy, \u017ce do test\u00f3w i na etapie pracy nad kodem b\u0119dziemy <strong>u\u017cywa\u0107 stuba <\/strong>(czyt. staba) \u2013 aplikacji, kt\u00f3ra b\u0119dzie zwraca\u0142a predefiniowane odpowiedzi).<\/p>\n\n\n\n<p>Lista wymaga\u0144 wobec naszego zamiennika by\u0142a bardzo kr\u00f3tka:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Komunikacja musi odbywa\u0107 si\u0119 po TCP<\/strong><\/li>\n\n\n\n<li><strong>\u017b\u0105danie musi zwraca\u0107 oczekiwan\u0105 odpowied\u017a<\/strong><\/li>\n\n\n\n<li><strong>Serwer musi by\u0107 w stanie obs\u0142u\u017cy\u0107 r\u00f3wnoleg\u0142e \u017c\u0105dania<\/strong><\/li>\n<\/ul>\n\n\n\n<p>Gotowe rozwi\u0105zanie w .NET by\u0142o przygotowane tak, aby mo\u017cna je by\u0142o uruchomi\u0107 lokalnie na Dockerze.<\/p>\n\n\n\n<p>Po upewnieniu si\u0119, \u017ce stub spe\u0142nia nasze oczekiwania i bez ryzyka mo\u017ce zast\u0105pi\u0107 rzeczywist\u0105 integracj\u0119, postanowili\u015bmy u\u017cy\u0107 go do test\u00f3w E2E (ang. end to end), kt\u00f3re s\u0105 elementem pipeline\u2019u <a href=\"https:\/\/nearshore-it.eu\/pl\/artykuly\/kim-jest-devops-i-jak-wspiera-projekty-it\" data-type=\"URL\" data-id=\"https:\/\/nearshore-it.eu\/pl\/artykuly\/kim-jest-devops-i-jak-wspiera-projekty-it\" target=\"_blank\" rel=\"noreferrer noopener\">DevOps<\/a>. W tym celu trzeba by\u0142o aplikacj\u0119 umie\u015bci\u0107 gdzie\u015b na platformie Azure, z kt\u00f3rej korzystali\u015bmy.<\/p>\n\n\n<div class=\"image-with-text\">\n    <div class=\"container\">\n        <div class=\"tiles latest-news-once\">\n            <div class=\"tile\" style=\"max-height: unset; height: 350\">\n                <div class=\"tile-image\">\n                                            <img decoding=\"async\" src=\"https:\/\/nearshore-it.eu\/wp-content\/uploads\/2024\/09\/2021.11.03_jpro_cover-3_min_c-1.jpg\" alt=\"\" title=\"\">\n                                    <\/div>\n                <div class=\"tile-content fadeIn wow\">\n                    <h3>Azure Serverless workflow orchestration<\/h3>\n<p>Automatyzacja proces\u00f3w biznesowych jest naturaln\u0105 transformacj\u0105. Poznaj rozwi\u0105zanie oparte na Azure Durable Function, kt\u00f3re pozwoli ci przej\u015b\u0107 g\u0142adko przez ten proces.<\/p>\n<p><a href=\"https:\/\/nearshore-it.eu\/pl\/artykuly\/azure-serverless-workflow-orchestration\/\" class=\"btn btn-red btn-arrow\">Przeczytaj artyku\u0142<\/a><\/p>\n                <\/div>\n            <\/div>\n        <\/div>\n    <\/div>\n<\/div>\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"Komunikacja-po-TCP-\u2013-jakie-s\u0105-opcje?\">Komunikacja po TCP \u2013 jakie s\u0105 opcje?<\/h2>\n\n\n\n<p>Najwi\u0119ksz\u0105 trudno\u015bci\u0105 w znalezieniu odpowiedniego zasobu okaza\u0142 si\u0119 wymagany rodzaj protoko\u0142u, niewspierany przez serwisy bazuj\u0105ce g\u0142\u00f3wnie na komunikacji po HTTP. Jakie mieli\u015bmy opcje?<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li><strong>Maszyna wirtualna<\/strong> \u2013 mo\u017cna postawi\u0107 maszyn\u0119 wirtualn\u0105 i na niej uruchomi\u0107 aplikacj\u0119, ale wymaga\u0142oby to dodatkowej konfiguracji dost\u0119pu do maszyny oraz utrudnia\u0142o monitorowanie samej aplikacji.<\/li>\n\n\n\n<li><strong>Azure Kubernetes Services<\/strong> \u2013 kolejn\u0105 opcj\u0105 jest AKS, kt\u00f3ry daje spor\u0105 elastyczno\u015b\u0107 w kwestii automatyzacji zarz\u0105dzania infrastruktur\u0105, jednak na potrzeby prostego stuba jest to nadmiarowe rozwi\u0105zanie (wymaga\u0142oby odpowiedniej konfiguracji, a i tak nie wykorzystaliby\u015bmy wielu opcji, jakie oferuje).<\/li>\n\n\n\n<li><strong>Azure Container Instances <\/strong>\u2013 przegl\u0105daj\u0105c portfolio us\u0142ug Azure, natrafi\u0142em na informacj\u0119, \u017ce protok\u00f3\u0142 TCP jest dost\u0119pny dla Azure Container Instances. Wygl\u0105da\u0142o to na idealne rozwi\u0105zanie, kt\u00f3re mo\u017cna by\u0142oby w prosty spos\u00f3b uruchomi\u0107. Dodatkowym atutem by\u0142a \u0142atwo\u015b\u0107 monitorowania i fakt, \u017ce lokalnie stub dzia\u0142a\u0142 na kontenerze dockerowym.<\/li>\n<\/ol>\n\n\n\n<p><strong>Obejrzyj tak\u017ce wideo z&nbsp;serii BiteIT:<\/strong><\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"BiteIT #58: Let`s secure your App Service on Azure | Marcin Niesyn\" width=\"500\" height=\"281\" src=\"https:\/\/www.youtube.com\/embed\/fDSI_-OCCU8?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share\" referrerpolicy=\"strict-origin-when-cross-origin\" allowfullscreen><\/iframe>\n<\/div><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"Konfigurujemy-Azure-Container-Instances\">Konfigurujemy Azure Container Instances<\/h2>\n\n\n\n<p>Na potrzeby tego artyku\u0142u przygotowa\u0142em uproszczon\u0105 wersj\u0119 docelowego rozwi\u0105zania. Dzia\u0142a ono jak echo, zwracaj\u0105c otrzymane \u017c\u0105danie do nadawcy, i to w\u0142a\u015bnie t\u0119 aplikacj\u0119 b\u0119d\u0119 stara\u0142 si\u0119 udost\u0119pni\u0107 poprzez Azure Container Instances.<\/p>\n\n\n\n<p>Poni\u017cej fragment kodu serwera odpowiedzialny za obs\u0142ug\u0119 \u017c\u0105da\u0144.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">private void Echo(IAsyncResult result) \n\n{ \n\nvar listener = (TcpListener)result.AsynState!; \n\t \n\nif (!_active) \n\n     { \n\n          return \n\n \n     } \n \n     var client = listener.EndAcceptTcpClient(result); \n\n     _logger.LogInformation(\u201cClient connected from: {ip}\u201d, \n     client.Client.RemoteEndPoint); \n     _allDone.Set(); \n\n     Task.Run(async () => \n\n     { \n\n          using (var stream = client.GetStream()) \n\n          var buffer = _array.Pool.Rent(256); \n\n         Array.Pool.Return(await stream.Echo(buffer), clearArray: true); \n     } \n\n     client. Close(); \n\n     }); \n\n \n} <\/pre>\n\n\n\n<p>Jako osoby zajmuj\u0105ce si\u0119 wytwarzaniem oprogramowania powinni\u015bmy <strong>d\u0105\u017cy\u0107 do automatyzowania powtarzalnych czynno\u015bci<\/strong>, dlatego ca\u0142\u0105 konfiguracj\u0119 zasob\u00f3w umie\u015bci\u0142em <strong>w plikach Bicep<\/strong>. Takie rozwi\u0105zanie pozwala u\u017cywa\u0107 raz zdefiniowanej konfiguracji wielokrotnie podczas wdra\u017cania jej na platformie Azure.<\/p>\n\n\n\n<p>Podstawowa konfiguracja Azure Container Instances wymaga zdefiniowania:<\/p>\n\n\n\n<p>1. Zasob\u00f3w, z jakich mo\u017ce korzysta\u0107 skonteneryzowana aplikacja.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">resources: { \n\n     requests: {  \n\n          cpu: 1  \n\n          memoryInGB: 1  \n     } \n} <\/pre>\n\n\n\n<p>2. Lokalizacji obrazu, na podstawie kt\u00f3rego b\u0119dzie budowany kontener, wraz ze zdefiniowanymi portami zewn\u0119trznymi.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">image: '${containerRegistryName}\/tcp-server:latest\u2019 \n\nports: [  \n\n{ \n\nport: port \n\nprotocol 'TCP' \n\n} \n\n] <\/pre>\n\n\n\n<p>3. Dost\u0119pu do rejestru, na kt\u00f3rym znajduje si\u0119 obraz.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">imageRegistryCredentials: [ \n\n{ \n\nserver: containerRegistryName \n\nusername: registryUserName \n\npassword: registryPassword \n\n} \n\n] <\/pre>\n\n\n\n<p>4. Konfiguracji adresu IP.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">IpAddress: { \n\ntype: \u2018Public\u2019 \n\nports: [  \n\n    {  \n\nport: port \n\nprotocol: \u2018TCP\u2019  \n\n    } \n\n          ] \n\n} <\/pre>\n\n\n\n<p><strong>Najwa\u017cniejsza rzecz, o kt\u00f3rej trzeba pami\u0119ta\u0107, to aby wewn\u0119trzny port odpowiada\u0142 portowi zewn\u0119trznemu, inaczej komunikacja po TCP nie b\u0119dzie dzia\u0142a\u0107.<\/strong><\/p>\n\n\n\n<p>Poni\u017cej ca\u0142y plik Bicep dla konfiguracji Azure Container Instances:<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img decoding=\"async\" src=\"https:\/\/nearshore-it.eu\/wp-content\/uploads\/2024\/09\/TCP_01-762.png\" alt=\"plik Bicep dla konfiguracji Azure Container Instances:\" class=\"wp-image-8861\" title=\"\"><\/figure>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"Czas-na-testy\">Czas na testy<\/h2>\n\n\n\n<p>Po wdro\u017ceniu na \u015brodowisko Azure mogli\u015bmy upewni\u0107 si\u0119, \u017ce aplikacja dzia\u0142a i nas\u0142uchuje na \u017c\u0105dania.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" src=\"https:\/\/nearshore-it.eu\/wp-content\/uploads\/2024\/09\/blog_2023.02.08_graphic_1.png\" alt=\"Protok\u00f3\u0142 tcp zapewnia us\u0142ugi po\u0142\u0105czeniowe\" class=\"wp-image-69569\" title=\"\"><\/figure>\n<\/div>\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" src=\"https:\/\/nearshore-it.eu\/wp-content\/uploads\/2024\/09\/blog_2023.02.08_graphic_2.png\" alt=\"Segment tcp zawiera sum\u0119 kontroln\u0105\" class=\"wp-image-69571\" title=\"\"><\/figure>\n<\/div>\n\n\n<p>Do cel\u00f3w testowych napisa\u0142em prostego klienta TCP jako test w xUnit.&nbsp;<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">[Fact]  \n\npublic void MakeSingleCall() \n\n{ \n\nvar buffer = _arrayPool.Rent(256); \n\ntry \n\n{ \n\nusing var client = GetClient(); \n\nusing var stream = client.GetStream(); \n\nstream.Write(Encoding.UTF8.GetBytes(TestMessage)); \n\n \n\n          while (!stream.DataAvailable) \n\n          { \n\n               Thread.Sleep(1000); \n\n          } \n\n \n\n          StringBuilder sb = new(); \n\n          while (Stream.DataAvailable) \n\n         { \n\n         var readBytes = stream. Read(buffer); \n\n         Sb.Append(Encoding.UTF8.GetString(buffer[...readBytes])); \n\n         } \n\n         Assert.Equal(TestMessage, sb.ToString()); \n\n    } \n\n    finally   \n\n    { \n\n           _arrayPoolReturn(buffer); \n\n    } \n\n\n} <\/pre>\n\n\n\n<p>Do nawi\u0105zywania po\u0142\u0105czenia s\u0142u\u017cy prywatna metoda GetClient.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">private static TcpClient GetClient() \n\n{  \n\nvar socketException = new SocketException(); \n\nushort attempts = 0; \n\nwhile (attempts &lt; RetryAttempt) \n\n{ \n\ntry  \n\n{ \n\nTcpClient client = new (HostName, Port); \n\nreturn client; \n\n          } \n\n          catch (socketException  ex  \n\n          { \n\n          socketException = ex; \n\n                attempts++; \n\n                Thread.Sleap(TimeSpan.FromSeconds(Math.Pow(2,  attempts))); \n\n                continue;   \n\n \n\n          } \n\n     } \n\n     throw SocketException; \n\n} <\/pre>\n\n\n\n<p>Jak wida\u0107, test zako\u0144czy\u0142 si\u0119 sukcesem, a w logach kontenera mamy informacj\u0119 o nawi\u0105zaniu po\u0142\u0105czenia.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" src=\"https:\/\/nearshore-it.eu\/wp-content\/uploads\/2024\/09\/blog_2023.02.08_graphic_3.png\" alt=\"TCP\u00a0 pozwala przesy\u0142a\u0107 i odebra\u0107 dane mi\u0119dzy procesami\u00a0\" class=\"wp-image-69573\" title=\"\"><\/figure>\n<\/div>\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" src=\"https:\/\/nearshore-it.eu\/wp-content\/uploads\/2024\/09\/blog_2023.02.08_graphic_4.png\" alt=\" IP to identyfikator liczbowy\" class=\"wp-image-69577\" title=\"\"><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"Problem-zmiany-adresu-IP-po-prze\u0142adowaniu\u2026\">Problem zmiany adresu IP po prze\u0142adowaniu\u2026<\/h2>\n\n\n\n<p>M\u00f3g\u0142bym w tym momencie przej\u015b\u0107 do podsumowania, jako \u017ce mamy dzia\u0142aj\u0105c\u0105 aplikacj\u0119 w Azure pozwalaj\u0105c\u0105 na komunikacj\u0119 po TCP. Niestety <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/container-instances\/container-instances-stop-start\" data-type=\"URL\" data-id=\"https:\/\/learn.microsoft.com\/en-us\/azure\/container-instances\/container-instances-stop-start\" target=\"_blank\" rel=\"noreferrer noopener\">w dokumentacji Azure Container Instances<\/a> jest informacja, \u017ce <strong>adres IP mo\u017ce si\u0119 zmieni\u0107 w przypadku prze\u0142adowania zasobu<\/strong>, co z kolei jest wymagane, aby pobra\u0107 najnowsz\u0105 wersj\u0119 obrazu aplikacji. Ryzyko zmiany adresu stuba sprawia\u0142o, \u017ce testy E2E nie mog\u0142y by\u0107 cz\u0119\u015bci\u0105 pipeline\u2019u, poniewa\u017c istnia\u0142a mo\u017cliwo\u015b\u0107, \u017ce b\u0119d\u0105 fa\u0142szywie negatywne.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u2026i rozwi\u0105zanie tego problemu<\/h3>\n\n\n\n<p>\u017beby nie wymusza\u0107 na kliencie serwera TCP pilnowania i zmieniania adresu IP po prze\u0142adowaniu zasobu, nale\u017cy ten problem \u201eschowa\u0107\u201d i obs\u0142u\u017cy\u0107 wewn\u0119trznie poprzez infrastruktur\u0119. Na szcz\u0119\u015bcie Azure zapewnia rozwi\u0105zania pozwalaj\u0105ce to zrobi\u0107.<\/p>\n\n\n\n<p>Docelowa architektura prezentuje si\u0119 nast\u0119puj\u0105co:<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-full\"><img decoding=\"async\" src=\"https:\/\/nearshore-it.eu\/wp-content\/uploads\/2024\/09\/blog_2023.02.08_graphic_5.png\" alt=\" Czy Container Apps\u00a0 z TCP mo\u017ce by\u0107 nowym najcz\u0119\u015bciej stosowanym rozwi\u0105zaniem?\" class=\"wp-image-69579\" title=\"\"><\/figure>\n<\/div>\n\n\n<p>I sk\u0142ada si\u0119 z:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Publicznego IP<\/strong><\/li>\n\n\n\n<li><strong>Load balancera<\/strong><\/li>\n\n\n\n<li><strong>Sieci wirtualnej (VNet)<\/strong><\/li>\n\n\n\n<li><strong>Container registry<\/strong><\/li>\n\n\n\n<li><strong>Container instances<\/strong><\/li>\n<\/ul>\n\n\n\n<p>Konfiguracj\u0119 w plikach Bicep podzieli\u0142em na modu\u0142y per typ zasobu oraz jeden plik g\u0142\u00f3wny jako punkt startowy do postawienia wszystkich niezb\u0119dnych element\u00f3w.<\/p>\n\n\n\n<p>Aby zmniejszy\u0107 liczb\u0119 adres\u00f3w IP, jakie mog\u0105 zosta\u0107 przydzielone do kontenera, zdefiniowana podsie\u0107 ma tylko 8 adres\u00f3w, z czego 5 jest na wewn\u0119trzne potrzeby Azure, co zostawia nas z 3 dost\u0119pnymi adresami.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">resource virtualNetwork \u2018Microsoft.Network\/virtualNetworks@2022-05-01'  existing = { \n\nname:shared-vnet' \n\n} \n\n \n\nresource subnet \u2018Microsoft.Network\/virtualNetworks\/subnets@2022-05-01' = { \n\n   name\u2019tcp-server-sub' \n\n   parent: virtualNetwork \n\n   properties: { \n\n \t   \taddressPrefix: \u201810.1.2.0\/29 \n\ndelegations: [ \n\n   { \n\nname: ACIDelegationService\u2019  \n\nproperties: {  \n\n   serviceName: \u2018Microsoft.ContainerInstance\/containerGroups\u2019  \n\ntype: \u2018Microsoft.Network\/virtualNetworks\/subnets\/delegations\u2019 \n\n   } \n\n] \n\nprivateEndpointNetworkPolicies: \u2018Disabled\u2019 \n\nprivateLinkServiceNetworkPolicies: \u2018Enabled\u2019  \n\n   } \n\n   \t} \n\n \noutput subnetId string = subnet.id <\/pre>\n\n\n\n<p>Konfiguruj\u0105c load balancer, nale\u017cy ustawi\u0107 pul\u0119 dla dost\u0119pu do wewn\u0119trznego zasobu.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">backendAddressPools: [  \n\n     {  \n\n     name: \u2018tcp-server-be' \n\n     properties: {  \n\n     loadBalancerBackendAddresses: [  \n\n     { \n\n     name: \u2018tcp-server\u2019 \n\n         properties: { \n\n         ipAddress: backendPrivateIPAddress \n\n  \t     virtualNetwork: { \n\n         id:virtualNetworkId \n\n         } \n\n         } \n\n      } \n\n   ] \n\n } \n\n } \n\n] <\/pre>\n\n\n\n<p>Gdzie \u201eipAddress\u201d jest adresem dla Container Instances wewn\u0105trz podsieci.<\/p>\n\n\n\n<p>Dodatkowo zdefiniowa\u0142em sprawdzanie \u017cywotno\u015bci kontenera poprzez pr\u00f3bkowanie.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">probes: [ \n\n{ \n\nname: \u2018tcp-server-hc' \n\nproperties: {  \n\n   protocol: \u2018Tcp\u2019  \n\n   port: tcpPort \n\n   intervalInSeconds: 5  \n\n   numberOfProbes: 1  \n\n          } \n\n     } \n\n]  <\/pre>\n\n\n\n<p>Wszystkie te ustawienia s\u0105 niezb\u0119dne do ustalenia regu\u0142 przekierowywania ruchu z publicznego adresu IP na wewn\u0119trzne.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">loadBalancingRules: [ \n\n   { \n\nname:  \u2018tcp-server-lb-rule' \n\n   properties: { \n\nfrontendPort: tcpPort \n\n   protocol: \u2018Tcp\u2019 \n\n   backendPort: tcpPort \n\n   disableOutboundSnat: true \n\n   frontendIPConfiguration: { \n\nid: resourceId( \u2018Microsoft.Network\/loadBalancers\/frontendIPConfigurations\u2019, \u2018tcp-server-lb', \u2018tcp-server-fe' ) \n\n} \n\nbackendAddressPool: { \n\nid: resourceId( \u2018Microsoft.Network\/loadBalancers\/backendAddressPools\u2019, \u2018tcp-server-lb', \u2018tcp-server-be' ) \n\n} \n\nprobe: { \n\n   \tid: resourceId(\u2018 Microsoft.Network\/loadBalancers\/probes\u2019, \u2018tcp-server-lb', \u2018tcp-server-hc' ) \n\n     } \n\n    } \n\n } \n\n] <\/pre>\n\n\n\n<p>Jedyna zmiana w konfiguracji Container Instances dotyczy ustawie\u0144 adresu IP, kt\u00f3ry teraz jest prywatny i przydzielony z podsieci.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ipAddress: {  \n\ntype: \u2018Private\u2019  \n\nports: [ \n\n   { \n\nport: port  \n\nprotocol : \u2018TCP\u2019 \n\n        } \n\n     ] \n\n} \n\nsubnetIds:[ \n\n          {  \n\nid: subnetId \n\n} \n\n]     <\/pre>\n\n\n\n<p>Taka konfiguracja dalej wymaga pilnowania adresu IP po restarcie kontenera i upewniania si\u0119, \u017ce jest taki sam jak ustawiony na load balancerze, ale staje si\u0119 to problemem wewn\u0119trznym.<\/p>\n\n\n<div class=\"wp-block-image size-full\">\n<figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/nearshore-it.eu\/wp-content\/uploads\/2024\/09\/blog_2023.02.08_graphic_6.png\" alt=\" class=\" class=\"wp-image-69581\" title=\"\"><\/figure>\n<\/div>\n\n\n<div style=\"height:30px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n<div class=\"wp-block-image size-full\">\n<figure class=\"aligncenter\"><img decoding=\"async\" src=\"https:\/\/nearshore-it.eu\/wp-content\/uploads\/2024\/09\/blog_2023.02.08_graphic_7.png\" alt=\" class=\" class=\"wp-image-69583\" title=\"\"><\/figure>\n<\/div>\n\n\n<div style=\"height:25px\" aria-hidden=\"true\" class=\"wp-block-spacer\"><\/div>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"Container-Apps-z-TCP-jako-kolejny-etap-ewolucji\">Container Apps z TCP jako kolejny etap ewolucji<\/h2>\n\n\n\n<p>Pod koniec 2022 roku Azure da\u0142 mo\u017cliwo\u015b\u0107 <a href=\"https:\/\/learn.microsoft.com\/en-us\/azure\/container-apps\/ingress?tabs=bash#tcp\" data-type=\"URL\" data-id=\"https:\/\/learn.microsoft.com\/en-us\/azure\/container-apps\/ingress?tabs=bash#tcp\" target=\"_blank\" rel=\"noreferrer noopener\">skonfigurowania Container Apps <\/a>dla komunikacji po TCP w wersji zapoznawczej.<\/p>\n\n\n\n<p>Poniewa\u017c Azure Container Apps u\u0142atwia skalowanie oraz pozwala zautomatyzowa\u0107 podnoszenie wersji aplikacji po pojawieniu si\u0119 nowego obrazu w rejestrze, postanowi\u0142em si\u0119 temu przyjrze\u0107.<\/p>\n\n\n\n<p>Zgodnie z dokumentacj\u0105 nale\u017cy umie\u015bci\u0107 \u015brodowisko zarz\u0105dzane wewn\u0105trz podsieci. Istotne jest skonfigurowanie poprawnego zakresu CIDR \u2013 minimum \/23.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">resource virtualNetwork \u2018Microsoft.Network\/virtualNetworks@2055-05-01' existing = { \n\nname: \u2018shared-vnet\u2019 \n\n     } \n\n     resource subnet \u2018Microsoft.Network\/virtualNetworks\/subnets@2022-05-01 = { \n\n         name: \u2018tcp-server-ca-sub' \n\n         parent: virtualNetwork \n\n         properties: {  \n\n          addressPrefix: \u201810.1.0.0\/23\u2019 \n\n           } \n\n      } \n\noutput subnetId string = subnet.id  <\/pre>\n\n\n\n<p>Container Apps wymagaj\u0105 zdefiniowanego \u015brodowiska zarz\u0105dzanego. Jak ju\u017c wspomnia\u0142em, nale\u017cy je umie\u015bci\u0107 wewn\u0105trz podsieci, pami\u0119taj\u0105c o ustawieniu w\u0142a\u015bciwo\u015bci \u201e<strong>internal<\/strong>\u201d na false, aby aplikacja by\u0142a dost\u0119pna z zewn\u0105trz.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">vnetConfiguration: { \n\ninfrastructureSubnetId: subnetId \n\ninternal: false \n\n} <\/pre>\n\n\n\n<p>Sama konfiguracja Container Apps wymaga zdefiniowania:<\/p>\n\n\n\n<p>1. Szablonu dla rewizji, kt\u00f3r\u0105 chcemy uruchomi\u0107.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">template: {  \n\ncontainers: [  \n\n{ \n\n          env: [ \n\n          { \n\n          name: \u2018TcpServer_Port\u2019 \n\nvalue: \u2018${port}\u2019 \n\n      } \n\n    ] \n\n    image: \u2018${containerRegistryName}\/tcp-server:latest\u2019 \n\n    name: \u2018tcp-server\u2019 \n\n    probes: [ \n\n     { \n\n     periodseconds: 10 \n\n     successThreshold: 1  \n\n          tcpSocket: { \n\n         port: port \n\n     } \n\n     type: \u2018Liveness\u2019 \n\n    } \n\n] \n\nresources: { \n\ncpu: json(\u20180.25\u2019) \n\nmemory: \u20180.5Gi\u2019 \n\n} \n} \n\n] \n\nrevisionSuffix: guid(\u2018tcp-server') \n\n}   <\/pre>\n\n\n\n<p>        Doda\u0142em, oczywi\u015bcie, pr\u00f3bkowanie \u017cywotno\u015bci kontenera.<\/p>\n\n\n\n<p>2. Punktu wej\u015bcia dla komunikacji zewn\u0119trznej.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">ingress: { \n\nallowInsecure: false \n\n     exposedPort: port \n\n     external: true \n\n     targetPort: port \n\n     transport: \u2018tcp\u2019 \n\n} <\/pre>\n\n\n\n<p>3. Dost\u0119pu do Azure Container Registry, na kt\u00f3rym znajduje si\u0119 obraz aplikacji.<\/p>\n\n\n\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"\" data-enlighter-highlight=\"\" data-enlighter-linenumbers=\"\" data-enlighter-lineoffset=\"\" data-enlighter-title=\"\" data-enlighter-group=\"\">registries: [  \n\n   {  \n\nserver: ascoding.azurecr.io\u2019 \n\nusername: registryUsername \n\npasswordSecretRef:  registryPasswordSecretId \n\n   } \n\n] \n\nsecrets: [  \n\n   { \n\nname: registryPasswordSecretId \n\nvalue: registryPassword \n\n  } \n\n]  <\/pre>\n\n\n\n<p>Przydatnym dodatkiem jest mo\u017cliwo\u015b\u0107 przechowywania informacji wra\u017cliwych wewn\u0105trz zasobu, <strong>bez konieczno\u015bci pod\u0142\u0105czania zewn\u0119trznego Key Vaulta.<\/strong><\/p>\n\n\n\n<p>Po zako\u0144czonym wdro\u017ceniu okaza\u0142o si\u0119, \u017ce rozwi\u0105zanie Azure jest bardzo podobne do mojego.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/nearshore-it.eu\/wp-content\/uploads\/2024\/11\/blog_2023.02.08_graphic_8.png\" alt=\"\" title=\"\"><\/figure>\n<\/div>\n\n\n<p>I r\u00f3wnie\u017c dzia\u0142a.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter size-large\"><img decoding=\"async\" src=\"https:\/\/nearshore-it.eu\/wp-content\/uploads\/2024\/11\/blog_2023.02.08_graphic_9.png\" alt=\"\" title=\"\"><\/figure>\n<\/div>\n\n\n<h2 class=\"wp-block-heading\" id=\"Podsumowanie\">Podsumowanie<\/h2>\n\n\n\n<p>Azure Container Instances pozwala na <strong>szybkie uruchamianie skonteneryzowanych aplikacji,<\/strong> kt\u00f3re umo\u017cliwia zewn\u0119trzn\u0105 komunikacj\u0119 po TCP. Niestety, nie jest to rozwi\u0105zanie pozbawione wad (przypomnijmy: zmieniaj\u0105ce si\u0119 IP, brak skalowania), kt\u00f3re utrudniaj\u0105 skonfigurowanie \u015brodowiska i w przypadku prostych aplikacji mog\u0105 by\u0107 powodem do jego odrzucenia.&nbsp;<\/p>\n\n\n\n<p>Na szcz\u0119\u015bcie Azure wyszed\u0142 naprzeciw potrzebom u\u017cytkownik\u00f3w z now\u0105 us\u0142ug\u0105, jak\u0105 jest <strong>Container Apps, <\/strong>kt\u00f3ra jest relatywnie <strong>prosta do skonfigurowania i pozbawiona problem\u00f3w, <\/strong>na jakie trafimy korzystaj\u0105c z Container Instances. Warto mie\u0107 to rozwi\u0105zanie na uwadze i \u015bledzi\u0107 nowe mo\u017cliwo\u015bci, jakie zesp\u00f3\u0142 developer\u00f3w chmury Microsoft Azure b\u0119dzie do niego dodawa\u0142.&nbsp;&nbsp;<\/p>\n\n\n\n<p><strong>Przeczytaj tak\u017ce:<\/strong> <a href=\"https:\/\/nearshore-it.eu\/pl\/artykuly\/big-data-azure\/\">Big Data w chmurze Azure<\/a><\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Gdy rozwijamy aplikacj\u0119, cz\u0119sto zachodzi potrzeba integrowania jej z zewn\u0119trznymi systemami. Zdarza si\u0119, \u017ce komunikacja z nimi jest niestabilna albo sama konfiguracja wymusza posiadanie fizycznych urz\u0105dze\u0144, aby developer na etapie programowania m\u00f3g\u0142 ca\u0142o\u015bciowo przetestowa\u0107 rozwi\u0105zanie. Programuj\u0105c pod k\u0105tem komunikacji z urz\u0105dzeniem (gdy np. w kodzie jest jego adres IP), jeste\u015bmy zale\u017cni od jego funkcjonalno\u015bci i dost\u0119pno\u015bci. Dobr\u0105 praktyk\u0105 jest wtedy pewnego rodzaju odizolowanie naszego systemu, aby warunki zewn\u0119trzne nie wp\u0142ywa\u0142y na codzienn\u0105 prac\u0119 nad oprogramowaniem. Z tego artyku\u0142u dowiesz si\u0119, jak odpowiedzieli\u015bmy na to wyzwanie, wdra\u017caj\u0105c komunikacj\u0119 po TCP z wykorzystaniem Azure. Je\u017celi kiedykolwiek stan\u0105\u0142by\u015b przed zadaniem postawienia serwera TCP z wykorzystaniem Microsoft Azure, ten materia\u0142 przeprowadzi ci\u0119 przez ten proces krok po kroku.<\/p>\n","protected":false},"author":115,"featured_media":31158,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"iawp_total_views":15,"footnotes":""},"categories":[1,582],"tags":[576,566],"offering":[516],"class_list":["post-31131","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-artykuly","category-technologie","tag-cloud-engineering","tag-devops","offering-cloud-engineering"],"acf":[],"_links":{"self":[{"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/posts\/31131","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/users\/115"}],"replies":[{"embeddable":true,"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/comments?post=31131"}],"version-history":[{"count":9,"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/posts\/31131\/revisions"}],"predecessor-version":[{"id":33881,"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/posts\/31131\/revisions\/33881"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/media\/31158"}],"wp:attachment":[{"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/media?parent=31131"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/categories?post=31131"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/tags?post=31131"},{"taxonomy":"offering","embeddable":true,"href":"https:\/\/nearshore-it.eu\/pl\/wp-json\/wp\/v2\/offering?post=31131"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}