public AksStack() { var resourceGroup = new ResourceGroup("aks-rg"); var randomPassword = new RandomPassword("password", new RandomPasswordArgs { Length = 20, Special = true, }).Result; var sshPublicKey = new PrivateKey("ssh-key", new PrivateKeyArgs { Algorithm = "RSA", RsaBits = 4096, }).PublicKeyOpenssh; // Create the AD service principal for the K8s cluster. var adApp = new Application("aks"); var adSp = new ServicePrincipal("aksSp", new ServicePrincipalArgs { ApplicationId = adApp.ApplicationId }); var adSpPassword = new ServicePrincipalPassword("aksSpPassword", new ServicePrincipalPasswordArgs { ServicePrincipalId = adSp.Id, Value = randomPassword, EndDate = "2099-01-01T00:00:00Z", }); // Grant networking permissions to the SP (needed e.g. to provision Load Balancers). var assignment = new Assignment("role-assignment", new AssignmentArgs { PrincipalId = adSp.Id, Scope = resourceGroup.Id, RoleDefinitionName = "Network Contributor" }); // Create a Virtual Network for the cluster. var vnet = new VirtualNetwork("vnet", new VirtualNetworkArgs { ResourceGroupName = resourceGroup.Name, AddressSpaces = { "10.2.0.0/16" }, }); // Create a Subnet for the cluster. var subnet = new Subnet("subnet", new SubnetArgs { ResourceGroupName = resourceGroup.Name, VirtualNetworkName = vnet.Name, AddressPrefix = "10.2.1.0/24", }); // Now allocate an AKS cluster. var cluster = new KubernetesCluster("aksCluster", new KubernetesClusterArgs { ResourceGroupName = resourceGroup.Name, DefaultNodePool = new KubernetesClusterDefaultNodePoolArgs { Name = "aksagentpool", NodeCount = 3, VmSize = "Standard_B2s", OsDiskSizeGb = 30, VnetSubnetId = subnet.Id }, DnsPrefix = "sampleaks", LinuxProfile = new KubernetesClusterLinuxProfileArgs { AdminUsername = "******", SshKey = new KubernetesClusterLinuxProfileSshKeyArgs { KeyData = sshPublicKey, }, }, ServicePrincipal = new KubernetesClusterServicePrincipalArgs { ClientId = adApp.ApplicationId, ClientSecret = adSpPassword.Value, }, KubernetesVersion = "1.16.9", RoleBasedAccessControl = new KubernetesClusterRoleBasedAccessControlArgs { Enabled = true }, NetworkProfile = new KubernetesClusterNetworkProfileArgs { NetworkPlugin = "azure", DnsServiceIp = "10.2.2.254", ServiceCidr = "10.2.2.0/24", DockerBridgeCidr = "172.17.0.1/16", }, }); // Create a k8s provider pointing to the kubeconfig. var k8sProvider = new Pulumi.Kubernetes.Provider("k8s", new Pulumi.Kubernetes.ProviderArgs { KubeConfig = cluster.KubeConfigRaw }); var customResourceOptions = new CustomResourceOptions { Provider = k8sProvider }; // Create a Container Registry. var registry = new Registry("acregistry", new RegistryArgs { ResourceGroupName = resourceGroup.Name, Sku = "Basic", AdminEnabled = true }); // Build & push the sample application to the registry. var applicationName = "sample-application"; var imageName = registry.LoginServer.Apply(value => $"{value}/{applicationName}"); var image = new Image(applicationName, new ImageArgs { Build = "./SampleApplication", Registry = new ImageRegistry { Server = registry.LoginServer, Username = registry.AdminUsername, Password = registry.AdminPassword }, ImageName = imageName }, new ComponentResourceOptions { Provider = k8sProvider }); // Create a k8s secret for use when pulling images from the container registry when deploying the sample application. var dockerCfg = Output.All <string>(registry.LoginServer, registry.AdminUsername, registry.AdminPassword).Apply( values => { var r = new Dictionary <string, object>(); var server = values[0]; var username = values[1]; var password = values[2]; r[server] = new { email = "*****@*****.**", username, password }; return(r); }); var dockerCfgString = dockerCfg.Apply(x => Convert.ToBase64String(Encoding.UTF8.GetBytes(System.Text.Json.JsonSerializer.Serialize(x)))); var dockerCfgSecretName = "dockercfg-secret"; var dockerCfgSecret = new Pulumi.Kubernetes.Core.V1.Secret(dockerCfgSecretName, new SecretArgs { Data = { { ".dockercfg", dockerCfgString } }, Type = "kubernetes.io/dockercfg", Metadata = new ObjectMetaArgs { Name = dockerCfgSecretName, } }, customResourceOptions); // Deploy the sample application to the cluster. var labels = new InputMap <string> { { "app", $"app-{applicationName}" }, }; var deployment = new Pulumi.Kubernetes.Apps.V1.Deployment(applicationName, new DeploymentArgs { Spec = new DeploymentSpecArgs { Selector = new LabelSelectorArgs { MatchLabels = labels, }, Replicas = 1, Template = new PodTemplateSpecArgs { Metadata = new ObjectMetaArgs { Labels = labels, Name = applicationName }, Spec = new PodSpecArgs { Containers = new List <ContainerArgs> { new ContainerArgs { Name = applicationName, Image = image.ImageName, } }, ImagePullSecrets = new LocalObjectReferenceArgs { Name = dockerCfgSecretName } } } } }, customResourceOptions); // Create a new service. var service = new Pulumi.Kubernetes.Core.V1.Service(applicationName, new ServiceArgs { Metadata = new ObjectMetaArgs { Name = applicationName, Labels = labels }, Spec = new ServiceSpecArgs { Type = "LoadBalancer", Selector = deployment.Spec.Apply(x => x.Template.Metadata.Labels), Ports = new ServicePortArgs { Port = 80 } } }, customResourceOptions); this.KubeConfig = cluster.KubeConfigRaw; this.DockercfgSecretName = dockerCfgSecret.Metadata.Apply(x => x.Name); }
static Task <int> Main(string[] args) { return(Pulumi.Deployment.RunAsync(() => { var config = new Pulumi.Config(); var pw = config.RequireSecret("message"); var rawPw = config.Require("message"); var cmData = new CoreV1.ConfigMap("cmdata", new ConfigMapArgs { Data = new InputMap <string> { { "password", pw }, } }); var cmBinaryData = new CoreV1.ConfigMap("cmbinarydata", new ConfigMapArgs { BinaryData = new InputMap <string> { { "password", pw.Apply(v => Base64Encode(v)) }, } }); var sStringData = new CoreV1.Secret("sstringdata", new SecretArgs { StringData = new InputMap <string> { { "password", rawPw } } }); var sData = new CoreV1.Secret("sdata", new SecretArgs { Data = new InputMap <string> { { "password", Base64Encode(rawPw) } } }); var name = $"test-{RandomString()}"; var secretYAML = $@" apiVersion: v1 kind: Secret metadata: name: {name} stringData: password: {rawPw} "; var cg = new Yaml.ConfigGroup("example", new Yaml.ConfigGroupArgs { Yaml = secretYAML }); var cgSecret = cg.GetResource <CoreV1.Secret>(name); return new Dictionary <string, object> { { "cmData", cmData.Data }, { "cmBinaryData", cmData.BinaryData }, { "sStringData", sStringData.StringData }, { "sData", sStringData.Data }, { "cgData", cgSecret.Apply(v => v.Data) }, }; })); }
private static void SetupAppointmentApiInKubernetes(AzureResourceBag azureResources, AppointmentApiAzureResourceBag appointmentApiAzureResources, PetDoctorClusterOptions clusterOptions) { var customOpts = new CustomResourceOptions { DependsOn = azureResources.Cluster, Provider = azureResources.ClusterProvider }; var secret = new Secret(clusterOptions.AppointmentApi.SecretName, new SecretArgs { Metadata = new ObjectMetaArgs { Namespace = clusterOptions.Namespace, Name = clusterOptions.AppointmentApi.SecretName }, Kind = "Secret", ApiVersion = "v1", Type = "Opaque", Data = new InputMap <string> { { "keyvault-url", appointmentApiAzureResources.KeyVault.VaultUri.Apply(kvUrl => Convert.ToBase64String(Encoding.UTF8.GetBytes(kvUrl))) }, { "appinsights-instrumentationkey", azureResources.AppInsights.InstrumentationKey.Apply(key => Convert.ToBase64String(Encoding.UTF8.GetBytes(key))) } } }, customOpts); var appointmentApiPodIdentity = new CustomResource(clusterOptions.AppointmentApi.AadPodIdentityName, new AzureIdentityResourceArgs { Metadata = new ObjectMetaArgs { Name = clusterOptions.AppointmentApi.AadPodIdentityName }, Spec = new AzureIdentitySpecArgs { Type = 0, ResourceId = appointmentApiAzureResources.Identity.Id, ClientId = appointmentApiAzureResources.Identity.ClientId } }, customOpts); var appointmentApiPodIdentityBinding = new CustomResource(clusterOptions.AppointmentApi.AadPodIdentityBindingName, new AzureIdentityBindingResourceArgs { Metadata = new ObjectMetaArgs { Name = clusterOptions.AppointmentApi.AadPodIdentityBindingName }, Spec = new AzureIdentityBindingSpecArgs { AzureIdentity = clusterOptions.AppointmentApi.AadPodIdentityName, Selector = clusterOptions.AppointmentApi.AadPodIdentitySelector } }, new CustomResourceOptions { DependsOn = new InputList <Resource> { azureResources.Cluster, appointmentApiAzureResources.Identity }, Provider = azureResources.ClusterProvider }); var appointmentApiDeployment = new Deployment("appointment-api-deployment", new DeploymentArgs { ApiVersion = "apps/v1beta1", Kind = "Deployment", Metadata = new ObjectMetaArgs { Name = clusterOptions.AppointmentApi.DeploymentName, Namespace = clusterOptions.Namespace, Labels = new InputMap <string> { { "app", clusterOptions.AppointmentApi.DeploymentName }, { "aadpodidbinding", clusterOptions.AppointmentApi.AadPodIdentitySelector } } }, Spec = new DeploymentSpecArgs { Replicas = clusterOptions.AppointmentApi.ReplicaCount, Selector = new LabelSelectorArgs { MatchLabels = new InputMap <string> { { "app", clusterOptions.AppointmentApi.DeploymentName } } }, Template = new PodTemplateSpecArgs { Metadata = new ObjectMetaArgs { Labels = new InputMap <string> { { "app", clusterOptions.AppointmentApi.DeploymentName }, { "aadpodidbinding", clusterOptions.AppointmentApi.AadPodIdentitySelector } } }, Spec = new PodSpecArgs { Containers = new InputList <ContainerArgs> { new ContainerArgs { Name = clusterOptions.AppointmentApi.DeploymentName, Image = clusterOptions.AppointmentApi.Image, Ports = new InputList <ContainerPortArgs> { new ContainerPortArgs { ContainerPortValue = clusterOptions.AppointmentApi.Port, Protocol = "TCP" } }, ReadinessProbe = new ProbeArgs { HttpGet = new HTTPGetActionArgs { Port = clusterOptions.AppointmentApi.Port, Path = "/ready", Scheme = "HTTP" }, InitialDelaySeconds = 15, TimeoutSeconds = 2, PeriodSeconds = 10, FailureThreshold = 3 }, LivenessProbe = new ProbeArgs { HttpGet = new HTTPGetActionArgs { Port = clusterOptions.AppointmentApi.Port, Path = "/live", Scheme = "HTTP" }, InitialDelaySeconds = 30, TimeoutSeconds = 2, PeriodSeconds = 5, FailureThreshold = 3 }, Env = new InputList <EnvVarArgs> { new EnvVarArgs { Name = "ASPNETCORE_ENVIRONMENT", Value = "Production" }, new EnvVarArgs { Name = "KEYVAULT__URL", ValueFrom = new EnvVarSourceArgs { SecretKeyRef = new SecretKeySelectorArgs { Name = clusterOptions.AppointmentApi.SecretName, Key = "keyvault-url" } } }, new EnvVarArgs { Name = "APPLICATIONINSIGHTS__INSTRUMENTATIONKEY", ValueFrom = new EnvVarSourceArgs { SecretKeyRef = new SecretKeySelectorArgs { Name = clusterOptions.AppointmentApi.SecretName, Key = "appinsights-instrumentationkey" } } }, new EnvVarArgs { Name = "HOSTENV", Value = "K8S" }, new EnvVarArgs { Name = "PATH_BASE", Value = "api" } } } } } } } }, new CustomResourceOptions { DependsOn = new InputList <Resource> { azureResources.Cluster, appointmentApiAzureResources.Identity, appointmentApiPodIdentityBinding }, Provider = azureResources.ClusterProvider }); var appointmentApiService = new Service(clusterOptions.AppointmentApi.ServiceName, new ServiceArgs { ApiVersion = "v1", Kind = "Service", Metadata = new ObjectMetaArgs { Name = clusterOptions.AppointmentApi.ServiceName, Namespace = clusterOptions.Namespace }, Spec = new ServiceSpecArgs { Selector = new InputMap <string> { { "app", clusterOptions.AppointmentApi.DeploymentName } }, Type = "ClusterIP", ClusterIP = "None", Ports = new InputList <ServicePortArgs> { new ServicePortArgs { Name = "http", Protocol = "TCP", Port = 80, TargetPort = clusterOptions.AppointmentApi.Port } } } }, customOpts); var appointmentApiIngress = new Ingress(clusterOptions.AppointmentApi.IngressName, new IngressArgs { ApiVersion = "extensions/v1beta1", Kind = "Ingress", Metadata = new ObjectMetaArgs { Name = clusterOptions.AppointmentApi.IngressName, Namespace = clusterOptions.Namespace, Annotations = new InputMap <string> { { "kubernetes.io/ingress.class", "nginx" }, { "certmanager.k8s.io/cluster-issuer", "letsencrypt-prod" } } }, Spec = new IngressSpecArgs { Tls = new InputList <IngressTLSArgs> { new IngressTLSArgs { Hosts = new InputList <string> { clusterOptions.Domain }, SecretName = "tls-secret" } }, Rules = new InputList <IngressRuleArgs> { new IngressRuleArgs { Host = clusterOptions.Domain, Http = new HTTPIngressRuleValueArgs { Paths = new InputList <HTTPIngressPathArgs> { new HTTPIngressPathArgs { Path = "/api", Backend = new IngressBackendArgs { ServiceName = clusterOptions.AppointmentApi.ServiceName, ServicePort = clusterOptions.AppointmentApi.Port } } } } } } } }, customOpts); }