static Task <int> Main() { return(Deployment.RunAsync(() => { var config = new Config(); var nodeCount = config.GetInt32("nodeCount") ?? 2; var appReplicaCount = config.GetInt32("appReplicaCount") ?? 5; var domainName = config.Get("domainName"); var cluster = new KubernetesCluster("do-cluser", new KubernetesClusterArgs { Region = "sfo2", Version = "latest", NodePool = new KubernetesClusterNodePoolArgs { Name = "default", Size = "s-2vcpu-2gb", NodeCount = nodeCount } }); var k8sProvider = new Provider("do-k8s", new ProviderArgs { KubeConfig = cluster.KubeConfigs.Apply(array => array[0].RawConfig) }); var app = new Pulumi.Kubernetes.Apps.V1.Deployment("do-app-dep", new DeploymentArgs { Spec = new DeploymentSpecArgs { Selector = new LabelSelectorArgs { MatchLabels = { { "app", "app-nginx" } } }, Replicas = appReplicaCount, Template = new PodTemplateSpecArgs { Metadata = new ObjectMetaArgs { Labels = { { "app", "app-nginx" } } }, Spec = new PodSpecArgs { Containers = new ContainerArgs { Name = "nginx", Image = "nginx" } } } } }, new CustomResourceOptions { Provider = k8sProvider }); var appService = new Service("do-app-svc", new ServiceArgs { Spec = new ServiceSpecArgs { Type = "LoadBalancer", Selector = app.Spec.Apply(spec => spec.Template.Metadata.Labels), Ports = new ServicePortArgs { Port = 80 } } }, new CustomResourceOptions { Provider = k8sProvider }); var ingressIp = appService.Status.Apply(status => status.LoadBalancer.Ingress[0].Ip); if (!string.IsNullOrWhiteSpace(domainName)) { var domain = new Domain("do-domain", new DomainArgs { Name = domainName, IpAddress = ingressIp }); var cnameRecord = new DnsRecord("do-domain-cname", new DnsRecordArgs { Domain = domain.Name, Type = "CNAME", Name = "www", Value = "@" }); } return new Dictionary <string, object?> { { "ingressIp", ingressIp } }; })); }
public EksStack() { // Read back the default VPC and public subnets, which we will use. var vpc = Output.Create(Ec2.GetVpc.InvokeAsync(new Ec2.GetVpcArgs { Default = true })); var vpcId = vpc.Apply(vpc => vpc.Id); var subnet = vpcId.Apply(id => Ec2.GetSubnetIds.InvokeAsync(new Ec2.GetSubnetIdsArgs { VpcId = id })); var subnetIds = subnet.Apply(s => s.Ids); // Create an IAM role that can be used by our service's task. var eksRole = new Iam.Role("eks-iam-eksRole", new Iam.RoleArgs { AssumeRolePolicy = @"{ ""Version"": ""2008-10-17"", ""Statement"": [{ ""Sid"": """", ""Effect"": ""Allow"", ""Principal"": { ""Service"": ""eks.amazonaws.com"" }, ""Action"": ""sts:AssumeRole"" }] }" }); var eksPolicies = new Dictionary <string, string> { { "service-policy", "arn:aws:iam::aws:policy/AmazonEKSServicePolicy" }, { "cluster-policy", "arn:aws:iam::aws:policy/AmazonEKSClusterPolicy" } }; foreach (var(name, policy) in eksPolicies) { var taskExecAttach = new Iam.RolePolicyAttachment($"rpa-{name}", new Iam.RolePolicyAttachmentArgs { Role = eksRole.Name, PolicyArn = policy, }); } // Create an IAM role that can be used by our service's task. var nodeGroupRole = new Iam.Role("nodegroup-iam-role", new Iam.RoleArgs { AssumeRolePolicy = @"{ ""Version"": ""2008-10-17"", ""Statement"": [{ ""Sid"": """", ""Effect"": ""Allow"", ""Principal"": { ""Service"": ""ec2.amazonaws.com"" }, ""Action"": ""sts:AssumeRole"" }] }" }); var nodeGroupPolicies = new Dictionary <string, string> { { "worker", "arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy" }, { "cni", "arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy" }, { "registry", "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" } }; foreach (var(name, policy) in nodeGroupPolicies) { var taskExecAttach = new Iam.RolePolicyAttachment($"ngpa-{name}", new Iam.RolePolicyAttachmentArgs { Role = nodeGroupRole.Name, PolicyArn = policy, }); } var clusterSg = new Ec2.SecurityGroup("cluster-sg", new Ec2.SecurityGroupArgs { VpcId = vpcId, Egress = { new Ec2.Inputs.SecurityGroupEgressArgs { Protocol = "-1", FromPort = 0, ToPort = 0, CidrBlocks ={ "0.0.0.0/0" } } }, Ingress = { new Ec2.Inputs.SecurityGroupIngressArgs { Protocol = "tcp", FromPort = 80, ToPort = 80, CidrBlocks ={ "0.0.0.0/0" } } } }); var cluster = new Eks.Cluster("eks-cluster", new Eks.ClusterArgs { RoleArn = eksRole.Arn, VpcConfig = new ClusterVpcConfigArgs { PublicAccessCidrs = { "0.0.0.0/0", }, SecurityGroupIds = { clusterSg.Id, }, SubnetIds = subnetIds, }, }); var nodeGroup = new Eks.NodeGroup("node-group", new Eks.NodeGroupArgs { ClusterName = cluster.Name, NodeGroupName = "demo-eks-nodegroup", NodeRoleArn = nodeGroupRole.Arn, SubnetIds = subnetIds, ScalingConfig = new NodeGroupScalingConfigArgs { DesiredSize = 2, MaxSize = 2, MinSize = 2 }, }); this.Kubeconfig = GenerateKubeconfig(cluster.Endpoint, cluster.CertificateAuthority.Apply(x => x.Data), cluster.Name); var k8sProvider = new K8s.Provider("k8s-provider", new K8s.ProviderArgs { KubeConfig = this.Kubeconfig }, new CustomResourceOptions { DependsOn = { nodeGroup }, }); var appNamespace = new CoreV1.Namespace("app-ns", new NamespaceArgs { Metadata = new ObjectMetaArgs { Name = "joe-duffy", }, }, new CustomResourceOptions { Provider = k8sProvider, }); var appLabels = new InputMap <string> { { "app", "iac-workshop" } }; var deployment = new AppsV1.Deployment("app-dep", new DeploymentArgs { Metadata = new ObjectMetaArgs { Namespace = appNamespace.Metadata.Apply(x => x.Name), }, Spec = new DeploymentSpecArgs { Selector = new LabelSelectorArgs { MatchLabels = appLabels }, Replicas = 1, Template = new PodTemplateSpecArgs { Metadata = new ObjectMetaArgs { Labels = appLabels }, Spec = new PodSpecArgs { Containers = { new ContainerArgs { Name = "iac-workshop", Image = "jocatalin/kubernetes-bootcamp:v2", } } } } }, }, new CustomResourceOptions { Provider = k8sProvider, }); var service = new CoreV1.Service("app-service", new ServiceArgs { Metadata = new ObjectMetaArgs { Namespace = appNamespace.Metadata.Apply(x => x.Name), Labels = deployment.Spec.Apply(spec => spec.Template.Metadata.Labels), }, Spec = new ServiceSpecArgs { Type = "LoadBalancer", Ports = { new ServicePortArgs { Port = 80, TargetPort = 8080 }, }, Selector = deployment.Spec.Apply(spec => spec.Template.Metadata.Labels) }, }, new CustomResourceOptions { Provider = k8sProvider, }); this.Url = service.Status.Apply(status => status.LoadBalancer.Ingress[0].Hostname); }
public AksCluster(string name, AksClusterArgs args) : base("example:component:AksCluster", name) { var adApp = new Application("app", new ApplicationArgs { DisplayName = "aks-cosmos" }, new CustomResourceOptions { Parent = this }); var adSp = new ServicePrincipal("service-principal", new ServicePrincipalArgs { ApplicationId = adApp.ApplicationId }, new CustomResourceOptions { Parent = this }); var pw = new RandomPassword("pw", new RandomPasswordArgs { Length = 20, Special = true }, new CustomResourceOptions { Parent = this }); var adSpPassword = new ServicePrincipalPassword("sp-password", new ServicePrincipalPasswordArgs { ServicePrincipalId = adSp.Id, Value = pw.Result, EndDate = "2099-01-01T00:00:00Z" }, new CustomResourceOptions { Parent = this }); var keyPair = new PrivateKey("ssh-key", new PrivateKeyArgs { Algorithm = "RSA", RsaBits = 4096 }, new CustomResourceOptions { Parent = this }); var k8sCluster = new ManagedCluster(name, new ManagedClusterArgs { ResourceGroupName = args.ResourceGroupName, AddonProfiles = { ["KubeDashboard"] = new ManagedClusterAddonProfileArgs { Enabled = true } }, AgentPoolProfiles = { new ManagedClusterAgentPoolProfileArgs { Count = args.NodeCount, VmSize = args.NodeSize, MaxPods = 110, Mode = "System", Name = "agentpool", OsDiskSizeGB = 30, OsType = "Linux", Type = "VirtualMachineScaleSets" } }, DnsPrefix = args.ResourceGroupName, EnableRBAC = true, KubernetesVersion = args.KubernetesVersion, LinuxProfile = new ContainerServiceLinuxProfileArgs { AdminUsername = "******", Ssh = new ContainerServiceSshConfigurationArgs { PublicKeys = new ContainerServiceSshPublicKeyArgs { KeyData = keyPair.PublicKeyOpenssh } } }, NodeResourceGroup = $"{name}-node-rg", ServicePrincipalProfile = new ManagedClusterServicePrincipalProfileArgs { ClientId = adApp.ApplicationId, Secret = adSpPassword.Value } }, new CustomResourceOptions { Parent = this }); this.ClusterName = k8sCluster.Name; this.KubeConfig = Output.Tuple(k8sCluster.Name, args.ResourceGroupName.ToOutput()) .Apply(pair => { var k8sClusterName = pair.Item1; var resourceGroupName = pair.Item2; return(ListManagedClusterUserCredentials.InvokeAsync(new ListManagedClusterUserCredentialsArgs { ResourceGroupName = resourceGroupName, ResourceName = k8sClusterName })); }) .Apply(x => x.Kubeconfigs[0].Value) .Apply(Convert.FromBase64String) .Apply(Encoding.UTF8.GetString); this.Provider = new K8s.Provider("k8s-provider", new K8s.ProviderArgs { KubeConfig = this.KubeConfig }, new CustomResourceOptions { Parent = this }); }
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); }
public MyCluster(MyConfig cfg) { var resourceGroup = new ResourceGroup("rg"); var adApp = new Application("app", new ApplicationArgs { DisplayName = "app" }); var adSp = new ServicePrincipal("service-principal", new ServicePrincipalArgs { ApplicationId = adApp.ApplicationId }); var adSpPassword = new ServicePrincipalPassword("sp-password", new ServicePrincipalPasswordArgs { ServicePrincipalId = adSp.Id, Value = cfg.Password, EndDate = "2099-01-01T00:00:00Z" }); var k8sCluster = new ManagedCluster("cluster", new ManagedClusterArgs { ResourceGroupName = resourceGroup.Name, AddonProfiles = { ["KubeDashboard"] = new ManagedClusterAddonProfileArgs { Enabled = true } }, AgentPoolProfiles = { new ManagedClusterAgentPoolProfileArgs { Count = cfg.NodeCount, VmSize = cfg.NodeSize, MaxPods = 110, Mode = "System", Name = "agentpool", OsDiskSizeGB = 30, OsType = "Linux", Type = "VirtualMachineScaleSets" } }, DnsPrefix = resourceGroup.Name, EnableRBAC = true, KubernetesVersion = cfg.K8SVersion, LinuxProfile = new ContainerServiceLinuxProfileArgs { AdminUsername = cfg.AdminUserName, Ssh = new ContainerServiceSshConfigurationArgs { PublicKeys = new ContainerServiceSshPublicKeyArgs { KeyData = cfg.SshPublicKey } } }, NodeResourceGroup = "node-resource-group", ServicePrincipalProfile = new ManagedClusterServicePrincipalProfileArgs { ClientId = adApp.ApplicationId, Secret = adSpPassword.Value } }); this.ClusterName = k8sCluster.Name; this.Kubeconfig = ListManagedClusterUserCredentials.Invoke( new ListManagedClusterUserCredentialsInvokeArgs { ResourceGroupName = resourceGroup.Name, ResourceName = k8sCluster.Name }) .Apply(x => x.Kubeconfigs[0].Value) .Apply(Convert.FromBase64String) .Apply(Encoding.UTF8.GetString); this.Provider = new K8s.Provider("k8s-provider", new K8s.ProviderArgs { KubeConfig = Kubeconfig }); }