0% found this document useful (0 votes)
26 views

Infrastructure as Code

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
26 views

Infrastructure as Code

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 65

Infrastructure as Code (IaC)

Bo-Yi Wu
2021/11/16
Pulumi vs Terraform
About me
• Software Engineer in Mediatek

• Member of Drone CI/CD Platform

• Member of Gitea Platform

• Member of Gin Golang Framework

• Maintain Some GitHub Actions Plugins.


What is
Infrastructure
As Code (IaC)?
Infrastructure as code is about
bringing software engineering
principles and approaches into
the cloud infrastructure space.
Move to
GCP or Azure?
為什麼需要 IaC

(避免⼈為操作失敗?)
IaC 帶來的好處?

• 建置 CI/CD ⾃動化 (不⽤依賴 UI 操作)

• 版本控制 (審核避免錯誤)

• 重複使⽤ (減少建置時間)

• 環境⼀⾄性 (測試及正式)

• 團隊成長 (分享學習資源)
⼯具選擇?
Terraform
• Domain Speci c Language of IaC Tool

• HCL for Terraform


fi
data "aws_ami" "ubuntu_16_04_docker" {

HCL 語法
f lter {
name = "name"
values = ["app base docker image *"]
}
f lter {
name = "virtualization type"
values = ["hvm"]
}
owners = ["161654634948"] # Canonical
}

resource "aws_instance" "foobar_api_01" {


ami = data.aws_ami.ubuntu_16_04_docker.id
instance_type = "t2.small"
vpc_security_group_ids = [aws_security_group.foobar_api.id]
key_name = aws_key_pair.foobar_deploy.key_name
subnet_id = aws_subnet.foobar_a.id
iam_instance_prof le = aws_iam_instance_prof le.ec2_role.id

tags = {
Name = "foobar api 01"
Project = "foobar"
Environment = var.environment["production"]
}
}
i
i
-
i
-
-
-
-
i
What if you need more logic?
• Conditionals

• If / else & logical operators

• Loops

• Functions

• re-use logic
_, err s3.NewBucket(ctx, "wms bucket", &s3.BucketArgs{
Acl: pulumi.String("private"),
Bucket: pulumi.String("objects.wms"),
ForceDestroy: pulumi.Bool(false),
LifecycleRules: s3.BucketLifecycleRuleArray{
&s3.BucketLifecycleRuleArgs{
Enabled: pulumi.Bool(true),
Expiration: &s3.BucketLifecycleRuleExpirationArgs{
Days: pulumi.Int(7),
},
Pref x: pulumi.String("backup"),
Tags: pulumi.StringMap{
"autoclean": pulumi.String("true"),
"name": pulumi.String("database"),
},
},
}, AWS S3 using Golang
}, pulumi.Protect(true))
:
=
i
-
Con guration by ENV
(AWS Global and China)
fi
Amazon FSx for Lustre
(Don’t support in China)
Conf g struct {
Logging Logging
Server Server
Database Database
Redis Redis
Storage Storage
Queue Queue
}

Database struct {
Driver string `envconf g:"APP_DATABASE_DRIVER"`
Username string `envconf g:"APP_DATABASE_USERNAME"`
Password string `envconf g:"APP_DATABASE_PASSWORD"`
Name string `envconf g:"APP_DATABASE_NAME"`
}
i
i
i
i
i
Pulumi Support Language
• Golang

• C#

• Python

• JavaScript

• TypeScript

• F#

• VB
Terraform
就不能⽤程式語⾔來寫?
https: github.com/hashicorp/terraform cdk
/
/
-
Pulumi
Cloud Provider
Converting From Terraform
Using tf2pulumi Tool
Using Pulumi and Terraform
Side-by-Side from
Terraform state
import * as pulumi from "@pulumi/pulumi"
import * as terraform from "@pulumi/terraform"

const con g = new pulumi.Con g()


const tfeToken = con g.requireSecret("tfeToken")

const networkState = new terraform.state.RemoteStateReference("network",


backendType: "remote"
token: tfeToken
organization: "acme"
workspaces:
name: "production-network"
}
})
;

fi
{

fi
,

fi
;

⾃⾏開發整合⼯具?
(Automation API)
https: .pulumi.com/blog/automation api/
/
/
w
w
w
-
YA! 不⽤使⽤ CLI Tool
(pulumi command)
Automation API allows you to embed Pulumi within your application code
1. Database Migration
_, err = rds.NewClusterInstance(ctx, "dbInstance", &rds.ClusterInstanceArgs{
ClusterIdentif er: cluster.ClusterIdentif er,
InstanceClass: rds.InstanceType_T3_Small,
Engine: rds.EngineTypeAuroraMysql,
EngineVersion: pulumi.String("5.7.mysql_aurora.2.03.2"),
PubliclyAccessible: pulumi.Bool(true),
DbSubnetGroupName: subnetGroup.Name,
})
if err nil {
return err
}

ctx.Export("host", cluster.Endpoint)
ctx.Export("dbName", dbName)
ctx.Export("dbUser", dbUser)
ctx.Export("dbPass", dbPass)
!
=
i
i
create our stack with an "inline" Pulumi program (deployFunc)
stack auto.UpsertStackInlineSource(ctx, stackName, projectName, deployFunc)
run the update to deploy our database
res, err stack.Up(ctx, stdoutStreamer)

fmt.Println("Update succeeded!")

get the connection info


host res.Outputs["host"].Value
dbName res.Outputs["dbName"].Value
dbUser res.Outputs["dbUser"].Value
dbPass res.Outputs["dbPass"].Value

establish db connection
db sql.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:3306)/%s", dbUser, dbPass, host, dbName))
defer db.Close()

run our database "migration"


fmt.Println("creating table ")
db.Query(`
CREATE TABLE IF NOT EXISTS hello_pulumi(
id int(9) NOT NULL,
color varchar(14) NOT NULL,
PRIMARY KEY(id)
);
`)
/
/
/
/
/
/
/
/
/
/
:
=
:
:
=
=
:
:
:
=
=
=
:
=
.
.
.
2. RESTful API Service
ctx context.Background()

stackName createReq.ID
program createPulumiProgram(createReq.Content)

s, err auto.NewStackInlineSource(ctx, stackName, project, program)


if err nil {
if stack already exists, 409
if auto.IsCreateStack409Error(err) {
w.WriteHeader(409)
fmt.Fprintf(w, fmt.Sprintf("stack %q already exists", stackName))
return
}

w.WriteHeader(500)
fmt.Fprintf(w, err.Error())
return
}
s.SetConf g(ctx, "aws:region", auto.Conf gValue{Value: "us west-2"})

deploy the stack


we'll write all of the update logs to st out so we can watch requests get processed
upRes, err s.Up(ctx, optup.ProgressStreams(os.Stdout))
if err nil {
w.WriteHeader(500)
fmt.Fprintf(w, err.Error())
return
}
/
/
/
/
/
/
:
=
:
!
!
:
=
=
=
=
i
:
=
:
=
i
-
State Management
Why I Choose
Pulumi?
開發者

• 可以使⽤熟悉的語⾔, 不⽤學習新語法

• 模組及跨平台 (AWS, GCP, Azure)

• 減少複製流程, ⾃由建立模組清單
DevOps 團隊

• Infrastructure as Code (可審核檢視)

• Multi-Cloud DevOps (⽤⼀種⽅式管理多個雲平台)

• Deploy Continuously (⾃動化部署)


資安團隊

• Policy as Code

• Built-In Secrets (加密特定資料: DB 密碼 ..)

• Enforce Standards (同⼀套流程管理系統架構)


Pulumi
Architecture
Pulumi Overview
Pulumi Overview
name: footer conf g:
runtime: go aws:prof le: footer
description: A minimal AWS Go Pulumi program aws:region: ap southeast-1
template: project:environment: production
conf g: project:name: footer
aws:region: pulumi:template: aws go
description: AWS region
default: ap southeast-1
i
i
i
-
-
-
package main

import (
"github.com/pulumi/pulumi aws/sdk/v4/go/aws/s3"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
pulumi.Run(func(ctx pulumi.Context) error {
Create an AWS resource (S3 Bucket)
bucket, err s3.NewBucket(ctx, "my bucket", nil)
if err nil {
return err
}

Export the name of the bucket


ctx.Export("bucketName", bucket.ID())
return nil
})
}
/
/
/
/
!
=
:
=
*
-
-
Pulumi CLI Console
Pulumi Cloud Console
Pulumi Cloud Console
Pulumi Cloud Console
Pulumi Cloud Console
快速建置簡單網⾴
使⽤ AWS S3 + Static
Website
pulumi.Run(func(ctx pulumi.Context) error {
Create an AWS resource (S3 Bucket)
bucket, err s3.NewBucket(ctx, "my bucket", &s3.BucketArgs{
Website: s3.BucketWebsiteArgs{
IndexDocument: pulumi.String("index.html"),
},
})
if err nil {
return err
}

site getEnv(ctx, "s3:siteDir", "content")


f les, err ioutil.ReadDir(site)
if err nil {
return err
}

for _, item range f les {


name item.Name()
if _, err = s3.NewBucketObject(ctx, name, &s3.BucketObjectArgs{
Bucket: bucket.Bucket,
Source: pulumi.NewFileAsset(f lepath.Join(site, name)),
Acl: pulumi.String("public read"),
ContentType: pulumi.String(mime.TypeByExtension(path.Ext(f lepath.Join(site, name)))),
}); err nil {
return err
}
}

Export the name of the bucket


ctx.Export("bucketID", bucket.ID())
ctx.Export("bucketName", bucket.Bucket)
ctx.Export("bucketEndpoint", bucket.WebsiteEndpoint)

return nil
})
/
/
/
i
/
:
=
!
!
:
=
=
=
!
:
=
:
=
:
=
=
*
i
-
-
i
i
Pulumi Pricing
免費⽅案
Convince Your Boss
Thank You

You might also like