{"id":31863,"date":"2021-01-13T00:00:00","date_gmt":"2021-01-12T23:00:00","guid":{"rendered":"https:\/\/blexin.com\/?p=31863"},"modified":"2021-05-20T18:18:17","modified_gmt":"2021-05-20T16:18:17","slug":"integration-test-with-pulumi-and-azure-kubernetes-service","status":"publish","type":"post","link":"https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/","title":{"rendered":"Integration test with Pulumi and Azure Kubernetes Service"},"content":{"rendered":"\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"608\" data-attachment-id=\"31756\" data-permalink=\"https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/attachment\/1_21_1105x656-blog-c-2\/\" data-orig-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2021\/01\/1_21_1105x656-blog-C-.png?fit=1105%2C656&amp;ssl=1\" data-orig-size=\"1105,656\" data-comments-opened=\"0\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;,&quot;orientation&quot;:&quot;0&quot;}\" data-image-title=\"1_21_1105x656-blog-C-\" data-image-description=\"\" data-image-caption=\"\" data-large-file=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2021\/01\/1_21_1105x656-blog-C-.png?fit=1024%2C608&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2021\/01\/1_21_1105x656-blog-C-.png?resize=1024%2C608&#038;ssl=1\" alt=\"\" class=\"wp-image-31756\" srcset=\"https:\/\/blexin.com\/wp-content\/uploads\/2021\/01\/1_21_1105x656-blog-C--1024x608.png 1024w, https:\/\/blexin.com\/wp-content\/uploads\/2021\/01\/1_21_1105x656-blog-C--980x582.png 980w, https:\/\/blexin.com\/wp-content\/uploads\/2021\/01\/1_21_1105x656-blog-C--480x285.png 480w\" sizes=\"auto, (min-width: 0px) and (max-width: 480px) 480px, (min-width: 481px) and (max-width: 980px) 980px, (min-width: 981px) 1024px, 100vw\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">We are carrying out update activities on some products for one of our clients, gradually migrating to microservice architectures. One of these products has followed the policy of &#8220;do not touch what works&#8221; for a long time, and as a result, it becomes unmanageable over time. Some classes representing business logic have grown beyond measure, becoming very complex to modify, with insufficient test coverage and a business logic shared between the various domains that coexist in the same codebase.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">All these factors made it difficult to maintain the system, and it was therefore decided to gradually evolve the code into different services. Unfortunately, business logic has remained shared between domains, and, currently, this sharing is the most important problem.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To properly divide the logic between various (micro)services and continue to deploy value without introducing regressions or unexpected malfunctions, we need to make sure that the modifications do not change the expected behavior of the software and, as always, the best weapon is to have a codebase well covered by testing.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>Unit Tests<\/strong> are very useful for the purpose, but they are not enough to make us confident about the changes we make to the logic.&nbsp;We also need to be able to test the interactions between two or more generated (micro)services, performing them in a temporary environment as close as possible to the production one, called <strong>Ephemeral Environment<\/strong>. In other words, we need an<strong> Integration Test <\/strong>suite.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To succeed in our aim is very useful the concept of <strong>Infrastructure as Code<\/strong> (Iac), which consists of representing the infrastructure (network, virtual machine, load balancer, and connection) in a descriptive way through the code.&nbsp;Following the principle that the same code always generates the same library, the same model of Iac always generates the same environment every time it is applied.&nbsp;By describing our target environment, then, we can share the same configuration between development teams and operations.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We use an Iac framework to recreate an Ephemeral environment in which our services could run, simulating the production environment.&nbsp;This also allowed us to isolate all external dependencies outside the scope of our logic.&nbsp;Recreated the environment, we built an integration test suite that could validate logic and simplify the addition of new features to the product.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Among the many Iac frameworks on the market, <a rel=\"noreferrer noopener\" href=\"https:\/\/www.pulumi.com\" target=\"_blank\"><strong>Pulumi<\/strong><\/a>, was chosen, which provides a CLI, a runtime, libraries, and a hosting service that work together.&nbsp;It allows you to deliver, provision, update and manage infrastructure in the Cloud, supporting multiple languages, including Typescript, Javascript, Python, Go, and.NET, and their native tools, libraries, and package managers.&nbsp;Pulumi works on almost all cloud providers or alternatively on an instance of <strong>Kubernetes <\/strong>(k8s); wanting to test locally, we can then use <a href=\"https:\/\/minikube.sigs.k8s.io\/\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>minikube<\/strong><\/a>&nbsp;or <a rel=\"noreferrer noopener\" href=\"https:\/\/kind.sigs.k8s.io\/\" target=\"_blank\"><strong>kind<\/strong><\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">A Pulumi program has the following components:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Program: a set of files written in one of the languages of your choice;<\/li><li>Project: a directory containing the program with the associated metadata;<\/li><li>Stack: represents an instance of the project. Often each stack corresponds to different cloud environment.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s see how to deploy with Pulumi on <strong>Azure Kubernetes Service<\/strong> (AKS) and launch a test suite in the created environment. You can find the <a href=\"https:\/\/github.com\/ntonjeta\/pulumi_integration_examples\" target=\"_blank\" rel=\"noreferrer noopener\">full code here<\/a>. I slightly modified the classic example of guestbook to deploy in Kubernetes, starting from what <a rel=\"noreferrer noopener\" href=\"https:\/\/kubernetes.io\/docs\/tutorials\/stateless-application\/guestbook\/\" target=\"_blank\">you see here<\/a>.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We create the project Pulumi with the command:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; title: ; notranslate\" title=\"\">\n`pulumi new kubernetes-typescript`\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">In this way, we create a template for a Typescript project that can be deployed on a Kubernetes cluster. You must now install the components with the package manager of the selected language, in our case npm, and initialize a stack.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n```\nnpm install .\n\npulumi stack init azure\n```\n\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">In the generated template, we find the file Pulumi.yaml in which the general configurations are set. You can also have specific configurations for stacks, and to set a configuration, just give the command:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n```\npulumi config set password &lt;password&gt; --secret\n```\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Before seeing how to configure the deploy, let\u2019s take a look at the application. It is a simple guestbook that uses a Redis cluster to store messages left by the guests.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To develop the guestbook, we can use a local Redis service, maybe deployed with Docker, but to completely isolate the environment, I preferred to use a mock of Redis:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n```\nvar Redis = require(&#039;ioredis-mock&#039;)\nvar redis = new Redis({\n  data: {\n\t&#039;messages&#039;: &#x5B;message]\n  }\n})\n```\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Once the guestbook has been developed, we create a docker image that we will load onto an <strong>Azure Container Registry<\/strong> (ACR) connected to the Resource Group on which the <strong>AKS<\/strong> instance is also present.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s take a look at DockerFile:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n```\nFROM node:slim\n\nWORKDIR \/app\n\n## Copy package.json and package-lock.json before copy other files for better build caching\nCOPY &#x5B;&quot;.\/package.json&quot;, &quot;.\/package-lock.json&quot;, &quot;\/app\/&quot;]\nRUN npm install\n\nCOPY &#x5B; &quot;.&quot;, &quot;\/app\/&quot; ]\nEXPOSE 3000\nCMD &#x5B;&quot;npm&quot;, &quot;start&quot;]\n```\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s build the container and load it to ACR.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n```\ndocker build . --tag=guestbook:v1\ndocker tag guestbook:v1 &lt;my-acr-name&gt;.azurecr.io\/guestbook\ndocker push &lt;my-acr-name&gt;.azurecr.io\/guestbook\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Now let\u2019s see how Pulumi allows us to describe architecture programmatically. In the project inside the cloud folder, we find two files: index.ts and k8sjs.ts.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\nindex.js\n\n```\nimport * as pulumi from &quot;@pulumi\/pulumi&quot;;\nimport * as k8sjs from &quot;.\/k8sjs&quot;;\n\nconst config = new pulumi.Config();\n\nconst redisLeader = new k8sjs.ServiceDeployment(&quot;redis-leader&quot;, {\n\timage: &quot;redis&quot;,\n\tports: &#x5B;6379],\n});\n\nconst redisReplica = new k8sjs.ServiceDeployment(&quot;redis-replica&quot;, {\n\timage: &quot;pulumi\/guestbook-redis-replica&quot;,\n\tports: &#x5B;6379],\n});\n\nconst frontend = new k8sjs.ServiceDeployment(&quot;frontend&quot;, {\n\treplicas: 3,\n\timage: &quot;&lt;my-acr-name&gt;.azurecr.io\/guestbook:latest&quot;,\n\tports: &#x5B;3000],\n\tallocateIpAddress: true,\n});\n\nexport let frontendIp = frontend.ipAddress;\n```\n\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s notice that index.ts describes the high-level infrastructure, taking advantage of the <em>Servicedeployment <\/em>class created in k8sjs.ts. Two instances of Redis are defined in the code, of which one leader and one replica. In addition, a deployment of our application is specified, with replication set to 3, so you have redundancy in case of failures.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let&#8217;s see the <em>ServiceDeployment<\/em> class :<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n```\nimport * as k8s from &quot;@pulumi\/kubernetes&quot;;\nimport * as k8stypes from &quot;@pulumi\/kubernetes\/types\/input&quot;;\nimport * as pulumi from &quot;@pulumi\/pulumi&quot;;\n\n\/**\n * ServiceDeployment is an example abstraction that uses a class to fold together the common pattern of a Kubernetes Deployment and its associated Service object.\n *\/\nexport class ServiceDeployment extends pulumi.ComponentResource {\n\tpublic readonly deployment: k8s.apps.v1.Deployment;\n\tpublic readonly service: k8s.core.v1.Service;\n\tpublic readonly ipAddress?: pulumi.Output&lt;string&gt;;\n\n\tconstructor(name: string, args: ServiceDeploymentArgs, opts?: pulumi.ComponentResourceOptions) {\n    \tsuper(&quot;k8sjs:service:ServiceDeployment&quot;, name, {}, opts);\n\n    \tconst labels = { app: name };\n    \tconst container: k8stypes.core.v1.Container = {\n        \tname,\n        \timage: args.image,\n        \tresources: args.resources || { requests: { cpu: &quot;100m&quot;, memory: &quot;100Mi&quot; } },\n        \tenv: &#x5B;{ name: &quot;GET_HOSTS_FROM&quot;, value: &quot;dns&quot; }],\n        \tports: args.ports &amp;&amp; args.ports.map(p =&gt; ({ containerPort: p })),\n    \t};\n    \tthis.deployment = new k8s.apps.v1.Deployment(name, {\n        \tspec: {\n            \tselector: { matchLabels: labels },\n            \treplicas: args.replicas || 1,\n            \ttemplate: {\n                \tmetadata: { labels: labels },\n                \tspec: { containers: &#x5B; container ] },\n            \t},\n        \t},\n    \t}, { parent: this });\n\n    \tthis.service = new k8s.core.v1.Service(name, {\n        \tmetadata: {\n            \tname: name,\n            \tlabels: this.deployment.metadata.labels,\n        \t},\n        \tspec: {\n            \tports: args.ports &amp;&amp; args.ports.map(p =&gt; ({ port: p, targetPort: p })),\n            \tselector: this.deployment.spec.template.metadata.labels,\n            \ttype: args.allocateIpAddress ? ( &quot;LoadBalancer&quot;) : undefined,\n        \t},\n    \t}, { parent: this });\n\n    \tif (args.allocateIpAddress) {\n            \tthis.ipAddress = this.service.status.loadBalancer.ingress&#x5B;0].ip;\n           \t \n    \t}\n\t}\n}\n\nexport interface ServiceDeploymentArgs {\n\timage: string;\n\tresources?: k8stypes.core.v1.ResourceRequirements;\n\treplicas?: number;\n\tports?: number&#x5B;];\n\tallocateIpAddress?: boolean;\n}\n```\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">In this code, there is a class that uses Pulumi libraries to join two concepts of k8s: the deployment and the service.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In the deployment, if passed, the default number of replicates set to 1 is specified. If the flag <em>allocateIpAddress <\/em>is specified, the service will be configured as &#8220;Loadbalancer&#8221; and the assigned IP address will be exposed between the fields of the class. Otherwise, the type set to undefined simply exposes the IP address within the k8s cluster.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With Pulumi you can then develop the application and define the infrastructure design using the same language, in this case Javascript\/Typescript.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Let\u2019s now deploy our application on Azure, an operation that requires a single terminal command: <strong>pulumi up<\/strong>. You can also have a preview before deploying with the <strong>pulumi preview<\/strong> command, which shows us the changes that will be made without modifying the current deploy.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Pulumi also offers an integration test suite in Go: let\u2019s see an example of use in which we create an Ephemeral Environment and run tests.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n```\npackage examples\n\nimport (\n    &quot;bytes&quot;\n    &quot;encoding\/json&quot;\n    &quot;fmt&quot;\n    &quot;io&quot;\n    &quot;io\/ioutil&quot;\n    &quot;net\/http&quot;\n    &quot;os&quot;\n    &quot;path&quot;\n    &quot;testing&quot;\n    &quot;time&quot;\n\n    &quot;github.com\/pulumi\/pulumi\/pkg\/v2\/testing\/integration&quot;\n    &quot;github.com\/stretchr\/testify\/assert&quot;\n)\n\nfunc TestGuestbook(t *testing.T) {\n    cwd, err := os.Getwd()\n    if err != nil {\n   \t t.FailNow()\n    }\n\n    test := integration.ProgramTestOptions{\n   \t Dir:     \tpath.Join(cwd, &quot;cloud&quot;),\n   \t Quick:   \ttrue,\n   \t SkipRefresh: true,\n   \t ExtraRuntimeValidation: func(t *testing.T, stack integration.RuntimeValidationStackInfo) {\n   \t\t var frontend = stack.Outputs&#x5B;&quot;frontendIp&quot;].(string)\n   \t\t checkHTTPResult(t, frontend)\n   \t\t checkMessageEndpoint(t, frontend)\n   \t },\n    }\n    integration.ProgramTest(t, &amp;test)\n}\n\nfunc checkHTTPResult(t *testing.T, output interface{}) bool {\n    hostname := &quot;http:\/\/&quot; + output.(string) + &quot;:3000&quot;\n    body := doGet(t, hostname, 5*time.Minute)\n    if !assert.Contains(t, body, &quot;&lt;html&gt;&quot;) {\n   \t return false\n    }\n    return true\n}\n\ntype dataMessage struct {\n    messages &#x5B;]string\n}\n\nfunc checkMessageEndpoint(t *testing.T, output interface{}) bool {\n    hostname := &quot;http:\/\/&quot; + output.(string) + &quot;:3000\/messages&quot;\n\n    message := dataMessage{\n   \t messages: &#x5B;]string{&quot;a message&quot;},\n    }\n\n    request, err := json.Marshal(message)\n    if !assert.Nil(t, err) {\n   \t return false\n    }\n\n    body := doPost(t, hostname, bytes.NewBuffer(request), 5*time.Minute)\n\n    body = doGet(t, hostname, 5*time.Minute)\n    if !assert.JSONEq(t, &quot;{\\&quot;messages\\&quot;: &#x5B;]}&quot;, body) {\n   \t return false\n    }\n    return true\n}\n\n```\n<\/pre><\/div>\n\n\n<p class=\"wp-block-paragraph\">Merely giving the command <strong>go test<\/strong> from the command line, you can pull up the environment properly configured, run our tests defined in the option <em>ExtraRuntimeValidation<\/em>, and finally pull down the environment.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We have seen how, using Pulumi, you can pull up an infrastructure simply by writing Javascript\/Typescript code and how to perform integration tests using the tools made available by the same framework.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I wish I&#8217;ve intrigued you.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To the next article!<\/p>\n\n\n\n\n[et_pb_section global_module=\"26295\"][\/et_pb_section]\n","protected":false},"excerpt":{"rendered":"<p>Let&#8217;s see how to use Infrastructure as Code for  the provisioning and the testing in an integration environment<\/p>\n","protected":false},"author":196716249,"featured_media":31756,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_et_pb_use_builder":"off","_et_pb_old_content":"<!-- wp:image {\"id\":31755,\"sizeSlug\":\"large\",\"linkDestination\":\"none\"} -->\n<figure class=\"wp-block-image size-large\"><img src=\"https:\/\/blexin.com\/wp-content\/uploads\/2021\/01\/1_21_1105x656-blog-C--1024x608.png\" alt=\"\" class=\"wp-image-31756\"\/><\/figure>\n<!-- \/wp:image -->\n\n<!-- wp:paragraph -->\n<p>We are carrying out update activities on some products for one of our clients, gradually migrating to microservice architectures. One of these products has followed the policy of \"do not touch what works\" for a long time, and as a result, it becomes unmanageable over time. Some classes representing business logic have grown beyond measure, becoming very complex to modify, with insufficient test coverage and a business logic shared between the various domains that coexist in the same codebase.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>All these factors made it difficult to maintain the system, and it was therefore decided to gradually evolve the code into different services. Unfortunately, business logic has remained shared between domains, and, currently, this sharing is the most important problem.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>To properly divide the logic between various (micro)services and continue to deploy value without introducing regressions or unexpected malfunctions, we need to make sure that the modifications do not change the expected behavior of the software and, as always, the best weapon is to have a codebase well covered by testing.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p><strong>Unit Tests<\/strong> are very useful for the purpose, but they are not enough to make us confident about the changes we make to the logic.&nbsp;We also need to be able to test the interactions between two or more generated (micro)services, performing them in a temporary environment as close as possible to the production one, called <strong>Ephemeral Environment<\/strong>. In other words, we need an<strong> Integration Test <\/strong>suite.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>To succeed in our aim is very useful the concept of <strong>Infrastructure as Code<\/strong> (Iac), which consists of representing the infrastructure (network, virtual machine, load balancer, and connection) in a descriptive way through the code.&nbsp;Following the principle that the same code always generates the same library, the same model of Iac always generates the same environment every time it is applied.&nbsp;By describing our target environment, then, we can share the same configuration between development teams and operations.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>We use an Iac framework to recreate an Ephemeral environment in which our services could run, simulating the production environment.&nbsp;This also allowed us to isolate all external dependencies outside the scope of our logic.&nbsp;Recreated the environment, we built an integration test suite that could validate logic and simplify the addition of new features to the product.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Among the many Iac frameworks on the market, <a rel=\"noreferrer noopener\" href=\"https:\/\/www.pulumi.com\" target=\"_blank\"><strong>Pulumi<\/strong><\/a>, was chosen, which provides a CLI, a runtime, libraries, and a hosting service that work together.\u00a0It allows you to deliver, provision, update and manage infrastructure in the Cloud, supporting multiple languages, including Typescript, Javascript, Python, Go, and.NET, and their native tools, libraries, and package managers.\u00a0Pulumi works on almost all cloud providers or alternatively on an instance of <strong>Kubernetes <\/strong>(k8s); wanting to test locally, we can then use <a href=\"https:\/\/minikube.sigs.k8s.io\/\" target=\"_blank\" rel=\"noreferrer noopener\"><strong>minikube<\/strong><\/a>\u00a0or <a rel=\"noreferrer noopener\" href=\"https:\/\/kind.sigs.k8s.io\/\" target=\"_blank\"><strong>kind<\/strong><\/a>.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>A Pulumi program has the following components:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:list -->\n<ul><li>Program: a set of files written in one of the languages of your choice;<\/li><li>Project: a directory containing the program with the associated metadata;<\/li><li>Stack: represents an instance of the project. Often each stack corresponds to different cloud environment.<\/li><\/ul>\n<!-- \/wp:list -->\n\n<!-- wp:paragraph -->\n<p>Let\u2019s see how to deploy with Pulumi on <strong>Azure Kubernetes Service<\/strong> (AKS) and launch a test suite in the created environment. You can find the <a href=\"https:\/\/github.com\/ntonjeta\/pulumi_integration_examples\" target=\"_blank\" rel=\"noreferrer noopener\">full code here<\/a>. I slightly modified the classic example of guestbook to deploy in Kubernetes, starting from what <a rel=\"noreferrer noopener\" href=\"https:\/\/kubernetes.io\/docs\/tutorials\/stateless-application\/guestbook\/\" target=\"_blank\">you see here<\/a>.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>We create the project Pulumi with the command:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:syntaxhighlighter\/code -->\n<pre class=\"wp-block-syntaxhighlighter-code\">`pulumi new kubernetes-typescript`<\/pre>\n<!-- \/wp:syntaxhighlighter\/code -->\n\n<!-- wp:paragraph -->\n<p>In this way, we create a template for a Typescript project that can be deployed on a Kubernetes cluster. You must now install the components with the package manager of the selected language, in our case npm, and initialize a stack.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:syntaxhighlighter\/code {\"language\":\"csharp\"} -->\n<pre class=\"wp-block-syntaxhighlighter-code\">```\nnpm install .\n\npulumi stack init azure\n```\n<\/pre>\n<!-- \/wp:syntaxhighlighter\/code -->\n\n<!-- wp:paragraph -->\n<p>In the generated template, we find the file Pulumi.yaml in which the general configurations are set. You can also have specific configurations for stacks, and to set a configuration, just give the command:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:syntaxhighlighter\/code {\"language\":\"csharp\"} -->\n<pre class=\"wp-block-syntaxhighlighter-code\">```\npulumi config set password &lt;password> --secret\n```<\/pre>\n<!-- \/wp:syntaxhighlighter\/code -->\n\n<!-- wp:paragraph -->\n<p>Before seeing how to configure the deploy, let\u2019s take a look at the application. It is a simple guestbook that uses a Redis cluster to store messages left by the guests.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>To develop the guestbook, we can use a local Redis service, maybe deployed with Docker, but to completely isolate the environment, I preferred to use a mock of Redis:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:syntaxhighlighter\/code {\"language\":\"csharp\"} -->\n<pre class=\"wp-block-syntaxhighlighter-code\">```\nvar Redis = require('ioredis-mock')\nvar redis = new Redis({\n  data: {\n\t'messages': [message]\n  }\n})\n```<\/pre>\n<!-- \/wp:syntaxhighlighter\/code -->\n\n<!-- wp:paragraph -->\n<p>Once the guestbook has been developed, we create a docker image that we will load onto an <strong>Azure Container Registry<\/strong> (ACR) connected to the Resource Group on which the <strong>AKS<\/strong> instance is also present.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Let's take a look at DockerFile:<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:syntaxhighlighter\/code {\"language\":\"csharp\"} -->\n<pre class=\"wp-block-syntaxhighlighter-code\">```\nFROM node:slim\n\nWORKDIR \/app\n\n## Copy package.json and package-lock.json before copy other files for better build caching\nCOPY [\".\/package.json\", \".\/package-lock.json\", \"\/app\/\"]\nRUN npm install\n\nCOPY [ \".\", \"\/app\/\" ]\nEXPOSE 3000\nCMD [\"npm\", \"start\"]\n```<\/pre>\n<!-- \/wp:syntaxhighlighter\/code -->\n\n<!-- wp:paragraph -->\n<p>Let\u2019s build the container and load it to ACR.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:syntaxhighlighter\/code {\"language\":\"csharp\"} -->\n<pre class=\"wp-block-syntaxhighlighter-code\">```\ndocker build . --tag=guestbook:v1\ndocker tag guestbook:v1 &lt;my-acr-name>.azurecr.io\/guestbook\ndocker push &lt;my-acr-name>.azurecr.io\/guestbook<\/pre>\n<!-- \/wp:syntaxhighlighter\/code -->\n\n<!-- wp:paragraph -->\n<p>Now let\u2019s see how Pulumi allows us to describe architecture programmatically. In the project inside the cloud folder, we find two files: index.ts and k8sjs.ts.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:syntaxhighlighter\/code {\"language\":\"csharp\"} -->\n<pre class=\"wp-block-syntaxhighlighter-code\">index.js\n\n```\nimport * as pulumi from \"@pulumi\/pulumi\";\nimport * as k8sjs from \".\/k8sjs\";\n\nconst config = new pulumi.Config();\n\nconst redisLeader = new k8sjs.ServiceDeployment(\"redis-leader\", {\n\timage: \"redis\",\n\tports: [6379],\n});\n\nconst redisReplica = new k8sjs.ServiceDeployment(\"redis-replica\", {\n\timage: \"pulumi\/guestbook-redis-replica\",\n\tports: [6379],\n});\n\nconst frontend = new k8sjs.ServiceDeployment(\"frontend\", {\n\treplicas: 3,\n\timage: \"&lt;my-acr-name>.azurecr.io\/guestbook:latest\",\n\tports: [3000],\n\tallocateIpAddress: true,\n});\n\nexport let frontendIp = frontend.ipAddress;\n```\n<\/pre>\n<!-- \/wp:syntaxhighlighter\/code -->\n\n<!-- wp:paragraph -->\n<p>Let\u2019s notice that index.ts describes the high-level infrastructure, taking advantage of the <em>Servicedeployment <\/em>class created in k8sjs.ts. Two instances of Redis are defined in the code, of which one leader and one replica. In addition, a deployment of our application is specified, with replication set to 3, so you have redundancy in case of failures.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Let's see the <em>ServiceDeployment<\/em> class :<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:syntaxhighlighter\/code {\"language\":\"csharp\"} -->\n<pre class=\"wp-block-syntaxhighlighter-code\">```\nimport * as k8s from \"@pulumi\/kubernetes\";\nimport * as k8stypes from \"@pulumi\/kubernetes\/types\/input\";\nimport * as pulumi from \"@pulumi\/pulumi\";\n\n\/**\n * ServiceDeployment is an example abstraction that uses a class to fold together the common pattern of a Kubernetes Deployment and its associated Service object.\n *\/\nexport class ServiceDeployment extends pulumi.ComponentResource {\n\tpublic readonly deployment: k8s.apps.v1.Deployment;\n\tpublic readonly service: k8s.core.v1.Service;\n\tpublic readonly ipAddress?: pulumi.Output&lt;string>;\n\n\tconstructor(name: string, args: ServiceDeploymentArgs, opts?: pulumi.ComponentResourceOptions) {\n    \tsuper(\"k8sjs:service:ServiceDeployment\", name, {}, opts);\n\n    \tconst labels = { app: name };\n    \tconst container: k8stypes.core.v1.Container = {\n        \tname,\n        \timage: args.image,\n        \tresources: args.resources || { requests: { cpu: \"100m\", memory: \"100Mi\" } },\n        \tenv: [{ name: \"GET_HOSTS_FROM\", value: \"dns\" }],\n        \tports: args.ports &amp;&amp; args.ports.map(p => ({ containerPort: p })),\n    \t};\n    \tthis.deployment = new k8s.apps.v1.Deployment(name, {\n        \tspec: {\n            \tselector: { matchLabels: labels },\n            \treplicas: args.replicas || 1,\n            \ttemplate: {\n                \tmetadata: { labels: labels },\n                \tspec: { containers: [ container ] },\n            \t},\n        \t},\n    \t}, { parent: this });\n\n    \tthis.service = new k8s.core.v1.Service(name, {\n        \tmetadata: {\n            \tname: name,\n            \tlabels: this.deployment.metadata.labels,\n        \t},\n        \tspec: {\n            \tports: args.ports &amp;&amp; args.ports.map(p => ({ port: p, targetPort: p })),\n            \tselector: this.deployment.spec.template.metadata.labels,\n            \ttype: args.allocateIpAddress ? ( \"LoadBalancer\") : undefined,\n        \t},\n    \t}, { parent: this });\n\n    \tif (args.allocateIpAddress) {\n            \tthis.ipAddress = this.service.status.loadBalancer.ingress[0].ip;\n           \t \n    \t}\n\t}\n}\n\nexport interface ServiceDeploymentArgs {\n\timage: string;\n\tresources?: k8stypes.core.v1.ResourceRequirements;\n\treplicas?: number;\n\tports?: number[];\n\tallocateIpAddress?: boolean;\n}\n```<\/pre>\n<!-- \/wp:syntaxhighlighter\/code -->\n\n<!-- wp:paragraph -->\n<p>In this code, there is a class that uses Pulumi libraries to join two concepts of k8s: the deployment and the service.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>In the deployment, if passed, the default number of replicates set to 1 is specified. If the flag <em>allocateIpAddress <\/em>is specified, the service will be configured as \"Loadbalancer\" and the assigned IP address will be exposed between the fields of the class. Otherwise, the type set to undefined simply exposes the IP address within the k8s cluster.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>With Pulumi you can then develop the application and define the infrastructure design using the same language, in this case Javascript\/Typescript.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Let\u2019s now deploy our application on Azure, an operation that requires a single terminal command: <strong>pulumi up<\/strong>. You can also have a preview before deploying with the <strong>pulumi preview<\/strong> command, which shows us the changes that will be made without modifying the current deploy.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>Pulumi also offers an integration test suite in Go: let\u2019s see an example of use in which we create an Ephemeral Environment and run tests.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:syntaxhighlighter\/code {\"language\":\"csharp\"} -->\n<pre class=\"wp-block-syntaxhighlighter-code\">```\npackage examples\n\nimport (\n    \"bytes\"\n    \"encoding\/json\"\n    \"fmt\"\n    \"io\"\n    \"io\/ioutil\"\n    \"net\/http\"\n    \"os\"\n    \"path\"\n    \"testing\"\n    \"time\"\n\n    \"github.com\/pulumi\/pulumi\/pkg\/v2\/testing\/integration\"\n    \"github.com\/stretchr\/testify\/assert\"\n)\n\nfunc TestGuestbook(t *testing.T) {\n    cwd, err := os.Getwd()\n    if err != nil {\n   \t t.FailNow()\n    }\n\n    test := integration.ProgramTestOptions{\n   \t Dir:     \tpath.Join(cwd, \"cloud\"),\n   \t Quick:   \ttrue,\n   \t SkipRefresh: true,\n   \t ExtraRuntimeValidation: func(t *testing.T, stack integration.RuntimeValidationStackInfo) {\n   \t\t var frontend = stack.Outputs[\"frontendIp\"].(string)\n   \t\t checkHTTPResult(t, frontend)\n   \t\t checkMessageEndpoint(t, frontend)\n   \t },\n    }\n    integration.ProgramTest(t, &amp;test)\n}\n\nfunc checkHTTPResult(t *testing.T, output interface{}) bool {\n    hostname := \"http:\/\/\" + output.(string) + \":3000\"\n    body := doGet(t, hostname, 5*time.Minute)\n    if !assert.Contains(t, body, \"&lt;html>\") {\n   \t return false\n    }\n    return true\n}\n\ntype dataMessage struct {\n    messages []string\n}\n\nfunc checkMessageEndpoint(t *testing.T, output interface{}) bool {\n    hostname := \"http:\/\/\" + output.(string) + \":3000\/messages\"\n\n    message := dataMessage{\n   \t messages: []string{\"a message\"},\n    }\n\n    request, err := json.Marshal(message)\n    if !assert.Nil(t, err) {\n   \t return false\n    }\n\n    body := doPost(t, hostname, bytes.NewBuffer(request), 5*time.Minute)\n\n    body = doGet(t, hostname, 5*time.Minute)\n    if !assert.JSONEq(t, \"{\"messages\": []}\", body) {\n   \t return false\n    }\n    return true\n}\n\n```<\/pre>\n<!-- \/wp:syntaxhighlighter\/code -->\n\n<!-- wp:paragraph -->\n<p>Merely giving the command <strong>go test<\/strong> from the command line, you can pull up the environment properly configured, run our tests defined in the option <em>ExtraRuntimeValidation<\/em>, and finally pull down the environment.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>We have seen how, using Pulumi, you can pull up an infrastructure simply by writing Javascript\/Typescript code and how to perform integration tests using the tools made available by the same framework.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>I wish I've intrigued you.<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:paragraph -->\n<p>To the next article!<\/p>\n<!-- \/wp:paragraph -->\n\n<!-- wp:block {\"ref\":28384} \/-->\n\n<!-- wp:shortcode -->\n[divi_shortcode id=\"26295\"]\n<!-- \/wp:shortcode -->","_et_gb_content_width":"","_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","_crdt_document":"","inline_featured_image":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"_wpas_customize_per_network":false,"jetpack_post_was_ever_published":false},"categories":[688637524],"tags":[688637381,688637411],"class_list":["post-31863","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog-en","tag-azure-en","tag-testing-en"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.4 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Integration test with Pulumi and Azure Kubernetes Service - Blexin<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Integration test with Pulumi and Azure Kubernetes Service - Blexin\" \/>\n<meta property=\"og:description\" content=\"Let&#039;s see how to use Infrastructure as Code for the provisioning and the testing in an integration environment\" \/>\n<meta property=\"og:url\" content=\"https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/\" \/>\n<meta property=\"og:site_name\" content=\"Blexin\" \/>\n<meta property=\"article:published_time\" content=\"2021-01-12T23:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2021-05-20T16:18:17+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/i1.wp.com\/blexin.com\/wp-content\/uploads\/2021\/01\/1_21_1105x656-blog-C-.png?fit=1105%2C656&ssl=1\" \/>\n\t<meta property=\"og:image:width\" content=\"1105\" \/>\n\t<meta property=\"og:image:height\" content=\"656\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Antonio Tammaro\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Antonio Tammaro\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"8 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/integration-test-with-pulumi-and-azure-kubernetes-service\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/integration-test-with-pulumi-and-azure-kubernetes-service\\\/\"},\"author\":{\"name\":\"Antonio Tammaro\",\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/#\\\/schema\\\/person\\\/6e574a2e13d47c9167c5cfb475d9bfc5\"},\"headline\":\"Integration test with Pulumi and Azure Kubernetes Service\",\"datePublished\":\"2021-01-12T23:00:00+00:00\",\"dateModified\":\"2021-05-20T16:18:17+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/integration-test-with-pulumi-and-azure-kubernetes-service\\\/\"},\"wordCount\":1107,\"image\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/integration-test-with-pulumi-and-azure-kubernetes-service\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/blexin.com\\\/wp-content\\\/uploads\\\/2021\\\/01\\\/1_21_1105x656-blog-C-.png?fit=1105%2C656&ssl=1\",\"keywords\":[\"Azure\",\"Testing\"],\"articleSection\":[\"Blog\"],\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/integration-test-with-pulumi-and-azure-kubernetes-service\\\/\",\"url\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/integration-test-with-pulumi-and-azure-kubernetes-service\\\/\",\"name\":\"Integration test with Pulumi and Azure Kubernetes Service - Blexin\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/integration-test-with-pulumi-and-azure-kubernetes-service\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/integration-test-with-pulumi-and-azure-kubernetes-service\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/i0.wp.com\\\/blexin.com\\\/wp-content\\\/uploads\\\/2021\\\/01\\\/1_21_1105x656-blog-C-.png?fit=1105%2C656&ssl=1\",\"datePublished\":\"2021-01-12T23:00:00+00:00\",\"dateModified\":\"2021-05-20T16:18:17+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/#\\\/schema\\\/person\\\/6e574a2e13d47c9167c5cfb475d9bfc5\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/integration-test-with-pulumi-and-azure-kubernetes-service\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/integration-test-with-pulumi-and-azure-kubernetes-service\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/integration-test-with-pulumi-and-azure-kubernetes-service\\\/#primaryimage\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/blexin.com\\\/wp-content\\\/uploads\\\/2021\\\/01\\\/1_21_1105x656-blog-C-.png?fit=1105%2C656&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/blexin.com\\\/wp-content\\\/uploads\\\/2021\\\/01\\\/1_21_1105x656-blog-C-.png?fit=1105%2C656&ssl=1\",\"width\":1105,\"height\":656},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/blog-en\\\/integration-test-with-pulumi-and-azure-kubernetes-service\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/blexin.com\\\/en\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Integration test with Pulumi and Azure Kubernetes Service\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/#website\",\"url\":\"https:\\\/\\\/blexin.com\\\/en\\\/\",\"name\":\"Blexin\",\"description\":\"Con noi \u00e8 semplice\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/blexin.com\\\/en\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/blexin.com\\\/en\\\/#\\\/schema\\\/person\\\/6e574a2e13d47c9167c5cfb475d9bfc5\",\"name\":\"Antonio Tammaro\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ddb88ac3dfb067ae6f1592d451eab3587e41bbbe98325961161cc286844e8d0d?s=96&d=identicon&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ddb88ac3dfb067ae6f1592d451eab3587e41bbbe98325961161cc286844e8d0d?s=96&d=identicon&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/ddb88ac3dfb067ae6f1592d451eab3587e41bbbe98325961161cc286844e8d0d?s=96&d=identicon&r=g\",\"caption\":\"Antonio Tammaro\"},\"url\":\"https:\\\/\\\/blexin.com\\\/en\\\/author\\\/antonio-tammaroblexin-com\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Integration test with Pulumi and Azure Kubernetes Service - Blexin","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/","og_locale":"en_US","og_type":"article","og_title":"Integration test with Pulumi and Azure Kubernetes Service - Blexin","og_description":"Let's see how to use Infrastructure as Code for the provisioning and the testing in an integration environment","og_url":"https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/","og_site_name":"Blexin","article_published_time":"2021-01-12T23:00:00+00:00","article_modified_time":"2021-05-20T16:18:17+00:00","og_image":[{"width":1105,"height":656,"url":"https:\/\/i1.wp.com\/blexin.com\/wp-content\/uploads\/2021\/01\/1_21_1105x656-blog-C-.png?fit=1105%2C656&ssl=1","type":"image\/png"}],"author":"Antonio Tammaro","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Antonio Tammaro","Est. reading time":"8 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/#article","isPartOf":{"@id":"https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/"},"author":{"name":"Antonio Tammaro","@id":"https:\/\/blexin.com\/en\/#\/schema\/person\/6e574a2e13d47c9167c5cfb475d9bfc5"},"headline":"Integration test with Pulumi and Azure Kubernetes Service","datePublished":"2021-01-12T23:00:00+00:00","dateModified":"2021-05-20T16:18:17+00:00","mainEntityOfPage":{"@id":"https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/"},"wordCount":1107,"image":{"@id":"https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2021\/01\/1_21_1105x656-blog-C-.png?fit=1105%2C656&ssl=1","keywords":["Azure","Testing"],"articleSection":["Blog"],"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/","url":"https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/","name":"Integration test with Pulumi and Azure Kubernetes Service - Blexin","isPartOf":{"@id":"https:\/\/blexin.com\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/#primaryimage"},"image":{"@id":"https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/#primaryimage"},"thumbnailUrl":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2021\/01\/1_21_1105x656-blog-C-.png?fit=1105%2C656&ssl=1","datePublished":"2021-01-12T23:00:00+00:00","dateModified":"2021-05-20T16:18:17+00:00","author":{"@id":"https:\/\/blexin.com\/en\/#\/schema\/person\/6e574a2e13d47c9167c5cfb475d9bfc5"},"breadcrumb":{"@id":"https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/#primaryimage","url":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2021\/01\/1_21_1105x656-blog-C-.png?fit=1105%2C656&ssl=1","contentUrl":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2021\/01\/1_21_1105x656-blog-C-.png?fit=1105%2C656&ssl=1","width":1105,"height":656},{"@type":"BreadcrumbList","@id":"https:\/\/blexin.com\/en\/blog-en\/integration-test-with-pulumi-and-azure-kubernetes-service\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/blexin.com\/en\/"},{"@type":"ListItem","position":2,"name":"Integration test with Pulumi and Azure Kubernetes Service"}]},{"@type":"WebSite","@id":"https:\/\/blexin.com\/en\/#website","url":"https:\/\/blexin.com\/en\/","name":"Blexin","description":"Con noi \u00e8 semplice","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/blexin.com\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/blexin.com\/en\/#\/schema\/person\/6e574a2e13d47c9167c5cfb475d9bfc5","name":"Antonio Tammaro","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/ddb88ac3dfb067ae6f1592d451eab3587e41bbbe98325961161cc286844e8d0d?s=96&d=identicon&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/ddb88ac3dfb067ae6f1592d451eab3587e41bbbe98325961161cc286844e8d0d?s=96&d=identicon&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/ddb88ac3dfb067ae6f1592d451eab3587e41bbbe98325961161cc286844e8d0d?s=96&d=identicon&r=g","caption":"Antonio Tammaro"},"url":"https:\/\/blexin.com\/en\/author\/antonio-tammaroblexin-com\/"}]}},"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/blexin.com\/wp-content\/uploads\/2021\/01\/1_21_1105x656-blog-C-.png?fit=1105%2C656&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/pcyUBx-8hV","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/posts\/31863","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/users\/196716249"}],"replies":[{"embeddable":true,"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/comments?post=31863"}],"version-history":[{"count":14,"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/posts\/31863\/revisions"}],"predecessor-version":[{"id":32902,"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/posts\/31863\/revisions\/32902"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/media\/31756"}],"wp:attachment":[{"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/media?parent=31863"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/categories?post=31863"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blexin.com\/en\/wp-json\/wp\/v2\/tags?post=31863"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}