Ruby for Iac

Ruby for Iac

Roppongi.rb#2の発表資料です

F811665799e1139b63140b72f3e8631f?s=128

Genki Sugawara

November 02, 2016
Tweet

Transcript

  1. Ruby for IaC Genki Sugawara Roppongi.rb#2

  2. $ whoami • ܙൺणͷํ͔Βདྷ·ͨ͠ • github: winebarrel • twitter: @sgwr_dts

    • Rubyͱ͔AWSͱ͔
  3. None
  4. None
  5. Agenda 1. Codenize.tools 2. How to make tools 3. Ruby

    tools at Work
  6. Codenize.tools

  7. Codenize.tools • https://codenize.tools/ • AWSͳͲͷίʔυԽπʔϧू • Datadog΍MySQLͷπʔϧ΋͋Γ·͢ • ۀ຿ͰࠔͬͨλΠϛϯάͰద౰ʹ࡞੒

  8. ίʔυԽʁ

  9. ίʔυԽ αʔϏεͷεςʔλεΛίʔυͰදݱ͢Δ͜ͱ …ͱউखʹߟ͑ͯ·͢ɻ ʢग़య͕Α͘Θ͔Βͳ͍ʣ

  10. ίʔυԽ RoadworkerʹΑΔ Route53ͷίʔυԽͷҰྫ hosted_zone "example.com." do rrset "example.com.", "A" do

    ttl 300 resource_records( "127.0.0.1", "127.0.0.2" ) end end
  11. DEMO

  12. Կ͕͏Ε͍͠ͷ͔ʁ • ςΩετΛमਖ਼͢Δ͚ͩͷ ҆શͰ؆୯ͳঢ়ଶมߋ • GitΛ࢖ͬͨཤྺ؅ཧ • ϓϧϦΫΤετΛ࢖ͬͨϫʔΫϑϩʔ

  13. ίʔυԽྫᶃ: Security Group ec2 "vpc-XXXXXXXX" do security_group "default" do description

    "default VPC security group" ingress do permission :tcp, 22..22 do ip_ranges( "0.0.0.0/0", ) end
  14. ίʔυԽྫᶄ: IAM user "bob", :path => "/developer/" do groups( "Admin"

    ) policy "bob-policy" do {"Version"=>"2012-10-17", "Statement"=> [{"Action"=> ["s3:Get*",
  15. ίʔυԽྫ: MySQLϢʔβ user "scott", "%" do on "*.*" do grant

    "USAGE" end on "test.*" do grant "SELECT" grant "INSERT" end
  16. ͜Μͳ΋ͷΛࡉʑͱ࡞͍ͬͯ·͢

  17. ͳͥ࡞͔ͬͨʁ • ΦϖϛεͰMXϨίʔυ͕ਧͬඈͿ • ChefͬΆ͘DNSΛ؅ཧ͍ͨ͠ • Roadworker࡞ͬͨ • ࣅͨΑ͏ͳͷ࡞ͬͨ

  18. ͳͥRubyʁ Rubyͷॊೈੑ͕ ཉ͔͔ͬͨ͠Β …ͱ͍͏ϙϦγʔ͕͋ͬͨΘ͚Ͱ͸ͳ͘

  19. ͳͥRubyʁ • جຊతʹ͸ChefͷӨڹ • Puppet΍Chefʹ׳Ε͍ͯͨͷͰ YAMLͳͲΛ࢖͏ൃ૝͕ͳ͔ͬͨ • ޙ͔ΒʮԿͰ΋ग़དྷΔͳʯͱࢥͬͨ

  20. Α͍ͱ͜Ζ΋͋Γѱ͍ͱ͜Ζ΋͋Γ

  21. Α͍ͱ͜Ζ • ͖Ε͍ɻͰ͢ΑͶʁ ʢJS◦NͭΒ͍ʣ • ॊೈ • Πϯλʔωοτ͔ΒIPϦετΛऔಘ • ແؔ܎ͳπʔϧͷઃఆΛύʔε

    • etc...
  22. ѱ͍ͱ͜Ζ • ॊೈ • Τϥʔ͕Θ͔Γʹ͍͘ ʢվળ͸ͯ͠·͢…ʣ

  23. ͦΕTerraformͰʢry

  24. ͦΕTerraformͰʢry • ͦ΋ͦ΋࡞Γ࢝Ίͨͱ͖͸ ͳ͔ͬͨΜͰ͢Α • ϦϦʔε͞Εͨͱ͖ͷؾ࣋ͪ ʘ(^o^)ʗ

  25. ͦΕTerraformͰʢry ϙϦγʔͷҧ͍͸͋Γ·͢: • DSL͕ঢ়ଶ 㱻 tfstate • αʔϏε͔ΒΤΫεϙʔτ • ޷͖ͳํΛ࢖͏ͱΑ͍ͱࢥ͍·͢ʂ

  26. How to make tools

  27. Apply • API→Hash • DSL→Hash • Hashಉ࢜Λൺֱ • ࠩ෼ΛຒΊΔAPIΛͨͨ͘ •

    ͪΐ͏͔ΜͨΜ
  28. Export • API→Hash • Hash→DSL • ͪΐ͏͔ΜͨΜ

  29. ྫ: Mappru • https://github.com/winebarrel/mappru vpc "vpc-12345678" do route_table "foo-rt" do

    subnets "subnet-12345678" route destination_cidr_block: "0.0.0.0/0", gateway_id: "igw-12345678" route destination_cidr_block: "192.168.100.101/32", network_interface_id: "eni-12345678"
  30. Apply: API→Hash require 'aws-sdk' resource = Aws::EC2::Resource.new rt = resource.route_tables.first

    p tr.routes #=> #<Aws::Resources::Batch \ # resources=[ # #<Aws::EC2::Route # route_table_id="rtb-xxxxxxxx", # destination_cidr_block="10.0.0.0/16">,
  31. Apply: API→Hash aws-sdkͷग़ྗ͸ ͍͍ͩͨHashʹ͠΍͍͢Ͱ͢

  32. Apply: API→Hash class Mappru::Exporter ... def export result = {}

    @resource.route_tables.each do |rt| vpc_id = rt.vpc_id name = rt.tags... result[vpc_id][name] = export_route_table(rt) end result end def export_route_table(rt) { route_table_id: rt.id, subnets: export_subnets(rt.associations), }
  33. Apply: API→Hash {"vpc-xxxxxxxx"=> {"foo"=>{:route_table_id=>"rtb-xxxxxxxx", :routes=>[], :subnets=>[]}, "bar"=> {:route_table_id=>"rtb-xxxxxxxx", :routes=> [{:destination_cidr_block=>"0.0.0.0/0",

    :gateway_id=>"igw-xxxxxxxx", :network_interface_id=>nil, :vpc_peering_connection_id=>nil, :nat_gateway_id=>nil}, {:destination_cidr_block=>"192.168.100.102/32", :gateway_id=>nil, :network_interface_id=>"eni-xxxxxxxx", :vpc_peering_connection_id=>nil, :nat_gateway_id=>nil}], :subnets=>["subnet-xxxxxxxx", "subnet-xxxxxxxx"]}}}
  34. Apply: DSL→Hash class Mappru::DSL::Context attr_reader :result def initialize(&block) @result =

    {} instance_eval(&block) end def vpc(vpc_id, &block) @result[vpc_id] = Mappru::DSL::Context::VPC.new(vpc_id, &block).result end end
  35. Apply: DSL→Hash class Mappru::DSL::Context::VPC attr_reader :result def initialize(vpc_id, &block) @vpc_id

    = vpc_id @result = {} instance_eval(&block) end def route_table(name, &block) @result[name] = Mappru::DSL::Context::VPC::RouteTable.new(@vpc_id, name, &block).result end end
  36. Apply: ൺֱɾAPIίʔϧ ΤΫεϙʔτͯ͠ class Mappru::Client def apply(file) expected = load_file(file)

    actual = Mappru::Exporter.export(@client, @options) walk_vpcs(expected, actual) end
  37. Apply: ൺֱɾAPIίʔϧ VPCΛൺֱͯ͠ def walk_vpcs(expected, actual) expected.each do |vpc_id, expected_rts|

    actual_rts = actual.delete(vpc_id) if actual_rts walk_vpc(vpc_id, expected_rts, actual_rts) end end end
  38. Apply: ൺֱɾAPIίʔϧ ࠩҟ͕͋ͬͨΒAPIΛͨͨ͘ def walk_vpc(vpc_id, expected, actual) expected.each do |rt_name,

    expected_rt| actual_rt = actual.delete(rt_name) unless actual_rt actual_rt = @driver.create_route_table( vpc_id, rt_name, expected_rt)
  39. Export: Hash→DSL class Mappru::DSL::Converter def convert output_vpcs(@exported) end ...(தུ)... def

    output_vpc(vpc_id, rt_by_name) route_tables = output_route_tables(rt_by_name).strip <<-EOS vpc #{vpc_id.inspect} do #{route_tables} end EOS end
  40. πʔϧͷ࢓૊Έ • શମతʹ͍ͨͨ͜͠ͱ΍ͬͯ·ͤΜ • DSL·ΘΓ͕एׯख͙ؒΒ͍ • YAMLͱ͔࢖͑͹΋ͬͱָʹ࡞ΕΔ

  41. ͪͳDslhͱ͍͏΋ͷ͕͋Γ·ͯ͠ Dslh.eval do glossary do title "example glossary" GlossDiv {

    title "S" } end end # => {"glossary"=> # {"title"=>"example glossary", # "GlossDiv"=> # {"title"=>"S"}}}
  42. ͪͳDslhͱ͍͏΋ͷ͕͋Γ·ͯ͠ • https://github.com/winebarrel/dslh • HashΛRubyͰॻ͚ΔṖgem • HashΛRubyʹม׵͢Δ͜ͱ΋ग़དྷΔ • ָʹDLSॻ͚ΔͷͰօ͞Μ΋ੋඇ…

  43. Ruby tools at Work

  44. Ұ਎্ͷ౎߹ʹΑΓ ࠷ۙ͸৽͍͠AWSΞΧ΢ϯτͰ ৽͍͠αʔό؀ڥΛ࡞Δ͜ͱ͕ଟ͍Ͱ͢

  45. AWS؀ڥΛ࡞Δ

  46. AWS؀ڥΛ࡞Δ ϦϙδτϦ࡞Δ

  47. AWS؀ڥΛ࡞Δ KumogataͰVPCΛ࡞Δ template do AWSTemplateFormatVersion "2010-09-09" Resources do myVPC do

    Type "AWS::EC2::VPC" Properties do CidrBlock "10.0.0.0/16" EnableDnsSupport true EnableDnsHostnames true Tags [_{ Key "Name" Value "foo" }] end end # (ུ)
  48. AWS؀ڥΛ࡞Δ • ͬ͘͟Γͱͨ͠VPCߏ੒͚ͩςϯϓϨʔτ͔Β࡞Δ • VPCɺSubnetɺRouteTable… • Ϧιʔε͸CFnͷελοΫͱ͸ؔ࿈͚ͮͳ͍ • RouteTable͸ΤΫεϙʔτ͓ͯ͘͠ •

    ࡉʑͱ͍Ζ͍Ζʢsshͷ౿Έ୆ͱ͔NATͱ͔ʣ
  49. AWS؀ڥΛ࡞Δ route_table ├── foo_private_az-a.rtbl ├── foo_private_az-c.rtbl └── foo_public.rtbl vpc "vpc-xxxxxxxx"

    do route_table "healthcare private az-a" do subnets "subnet-xxxxxxxx" route destination_cidr_block: "0.0.0.0/0", nat_gateway_id: ... route destination_cidr_block: "10.10.0.0/16", vpc_peering_connection_id: ...
  50. AWS؀ڥΛ࡞Δ IAMͷϩʔϧΛ࡞Δ iam ├── groups ├── policies ├── roles │

    ├── admin.iam ├── templates └── users ├── sugawara.iam role "admin", :path=>"/" do attached_managed_policies( "arn:aws:iam::aws:policy/AdministratorAccess"
  51. AWS؀ڥΛ࡞Δ • εΠον͢Δϩʔϧ • ؅ཧϢʔβ • etc..

  52. AWS؀ڥΛ࡞Δ PackerͰAMI࡞Δ • جຊతʹAmazon Linux͔Β • EC2༻ͱECS༻ͷ2छྨ • ϓϩϏδϣχϯά͸֎෦γΣϧεΫϦϓτ ʢ্هͰڞ௨ʣ

    • جຊతͳπʔϧ͸ग़དྷΔ͚ͩೖΕΔํ਑
  53. AWS؀ڥΛ࡞Δ αʔόͷϩʔϧ(໾ׂ)͝ͱʹ * Security GroupΛ࡞Δ security_group/ ├── foo │ ├──

    app-internal.group │ ├── db-default.group
  54. AWS؀ڥΛ࡞Δ IPΞυϨεͱ͔͸ม਺ʹ·ͱΊ·͢ OFFICE = %w(10.0.0.1/32 10.0.0.2/32) ec2 "vpc-xxxxxxxx" do security_group

    "rproxy" do description "rproxy" ingress do permission :tcp, 80..80 do ip_ranges( *OFFICE,
  55. AWS؀ڥΛ࡞Δ αʔόͷϩʔϧ(໾ׂ)͝ͱʹ * IAMϩʔϧΛ࡞Δ iam ├── roles │ ├── ec2-app-internal.iam

    │ ├── ec2-rproxy.iam
  56. AWS؀ڥΛ࡞Δ ڞ௨ͷϙϦγʔ͸ςϯϓϨʔτʹ·ͱΊ·͢ɻ template "EC2Base" do attached_managed_policies( "arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess" ) end role

    "ec2-base", :path=>"/" do include_template "EC2Base"
  57. AWS؀ڥΛ࡞Δ RakeλεΫͰαʔόΛىಈ $ bundel exec rake ec2-bootstrap:new vim্ཱ͕͕ͪͬͯ ςϯϓϨʔτΛฤूͯ͠อଘ͢Δͱ ͦΕʹैͬͯΠϯελϯεΛͨͯΔRakeλεΫ

  58. AWS؀ڥΛ࡞Δ

  59. AWS؀ڥΛ࡞Δ Itamae੔උ itamae ├── cookbooks │ ├── bind-utils │ ├──

    datadog │ ├── datadog-docker │ ├── dstat │ ... └── roles ├── app-internal ├── base ├── batch ...
  60. AWS؀ڥΛ࡞Δ capͰαʔόʹద༻ bundel exec cap itamae:dry-run ROLES=rproxy bundel exec cap

    itamae:apply ROLES=rproxy
  61. AWS؀ڥΛ࡞Δ αʔόʹద༻͢ΔϨγϐ͸ base/default.rbͱ ͦͷαʔόͷRoleλάͰܾఆ itamae/roles/base/default.rb + itamae/roles/<Roleλά>/default.rb

  62. AWS؀ڥΛ࡞Δ include_cookbookͰ ΫοΫϒοΫΛinclude͢Δ include_cookbook 'nginx' #=> itamae/cookbooks/default.rb

  63. AWS؀ڥΛ࡞Δ Itamaeʹϩʔϧ΍ΫοΫϒοΫͱ͍͏ ࢓૊Έ͸ͳ͍ͷͰࣗલͰ࡞ΓࠐΈ… require 'pathname' module RecipeHelper ITAMAE_DIR = Pathname('..').expand_path(__FILE__)

    def include_role(name) recipe_file = 'default.rb' include_recipe ITAMAE_DIR.join('roles', name, recipe_file).to_s end def include_cookbook(name) recipe_file = 'default.rb' include_recipe ITAMAE_DIR.join('cookbooks', name, recipe_file).to_s end
  64. AWS؀ڥΛ࡞Δ rake͡Όͳͯ͘capΛ࢖͍ͬͯΔͷ͸ αʔό্Ͱitamae localΛ࣮ߦ͍ͯ͠ΔͨΊ

  65. AWS؀ڥΛ࡞Δ cap itamae:apply • αʔό্͔ΒGitHubͷϦϙδτϦΛ tarballͱͯ͠औಘˠద༻ cap itamae:apply USL_LOCAL=1 •

    ϩʔΧϧ؀ڥͷϦϙδτϦσΟϨΫτϦΛ tarballͱͯ͠S3ʹΞοϓϩʔυ • αʔό্ͰS3͔ΒtaballΛμ΢ϯϩʔυˠద༻
  66. AWS؀ڥΛ࡞Δ Πϯϑϥ৘ใ؅ཧ༻ͷYAML ϧʔτʹஔ͍͓͍͍ͯͯΖΜͳՕॴͰར༻͢Δ ip_address: nat: - 52.11.22.33 # ax-a -

    52.22.33.44 # az-c ssh_gw: - 52.123.111.222 ygp_office: - 122.11.12.13 elb: - ...
  67. AWS؀ڥΛ࡞Δ ELBͷϗετ໊Λ * Itamaeͷnginx.confͰ࢖͏ * Roadworker(Route53)ͷdns_nameͰ࢖͏ ΦϑΟεͷIPΞυϨεϦετΛ * Itamaeͷnginx.confͰ࢖͏ *

    Piculet(SG)ͷΞΫηε੍ޚͰ࢖͏ etc...
  68. AWS؀ڥΛ࡞Δ ൿಗ஋ʹ͍ͭͯ͸credstashͳͲΛ࢖ͬͯ·͢ • https://github.com/fugue/credstash • https://github.com/winebarrel/gcredstash • https://github.com/adorechic/rcredstash • https://github.com/adorechic/secret_env

    • https://github.com/adorechic/secret_console see KMS/DynamoDBΛ࢖ͬͨൿີύϥϝʔλͷอ؅ - Qiita
  69. AWS؀ڥΛ࡞Δ • Route53ΛΤΫεϙʔτ • Bucket PolicyΛΤΫεϙʔτ • CloudFrontΛΤΫεϙʔτ • DatadogΛΤΫεϙʔτ

    • MySQLϢʔβΛΤΫεϙʔτ • etc... ϦϙδτϦʹAWSઃఆΛͲΜͲΜ௥Ճ
  70. AWS؀ڥΛ࡞Δ ͋ͱ͸RakeλεΫΛ੔͑ͯ README.meΛ੔͑ͯ ։ൃϝϯόʔʹҾ͖౉͠…

  71. Έ͍ͨͳײ͡Ͱ πʔϧΛ׆༻͍ͯ͠·͢

  72. None