Pulumi๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ธํ”„๋ผ๋ฅผ ์ฝ”๋“œ๋กœ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค. 1 ๋ถ€

์ข‹์€ ์˜คํ›„ ์นœ๊ตฌ. ์ƒˆ๋กœ์šด ํ๋ฆ„์˜ ์‹œ์ž‘์„ ๊ธฐ๋Œ€ํ•˜๋ฉฐ "DevOps ์‚ฌ๋ก€ ๋ฐ ๋„๊ตฌ" ์šฐ๋ฆฌ๋Š” ์ƒˆ๋กœ์šด ๋ฒˆ์—ญ์„ ์—ฌ๋Ÿฌ๋ถ„๊ณผ ๊ณต์œ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ฐ€๋‹ค.

Pulumi๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ธํ”„๋ผ๋ฅผ ์ฝ”๋“œ๋กœ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค. 1 ๋ถ€

์ธํ”„๋ผ ์ฝ”๋“œ(์ฝ”๋“œ๋กœ์„œ์˜ ์ธํ”„๋ผ)์— Pulumi ๋ฐ ๋ฒ”์šฉ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๊ธฐ์ˆ  ๋ฐ ์ง€์‹์˜ ๊ฐ€์šฉ์„ฑ, ์ถ”์ƒํ™”๋ฅผ ํ†ตํ•œ ์ฝ”๋“œ์˜ ์ƒ์šฉ๊ตฌ ์ œ๊ฑฐ, IDE ๋ฐ ๋ฆฐํ„ฐ์™€ ๊ฐ™์ด ํŒ€์— ์นœ์ˆ™ํ•œ ๋„๊ตฌ ๋“ฑ ๋งŽ์€ ์ด์ ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ชจ๋“  ์†Œํ”„ํŠธ์›จ์–ด ์—”์ง€๋‹ˆ์–ด๋ง ๋„๊ตฌ๋Š” ์ƒ์‚ฐ์„ฑ์„ ๋†’์ผ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ฝ”๋“œ ํ’ˆ์งˆ๋„ ํ–ฅ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๋ฒ”์šฉ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋˜ ๋‹ค๋ฅธ ์ค‘์š”ํ•œ ์†Œํ”„ํŠธ์›จ์–ด ๊ฐœ๋ฐœ ๋ฐฉ์‹์„ ๋„์ž…ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์€ ๋‹น์—ฐํ•ฉ๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ.

์ด ๊ธฐ์‚ฌ์—์„œ๋Š” Pulumi๊ฐ€ ์ฝ”๋“œํ˜• ์ธํ”„๋ผ ํ…Œ์ŠคํŠธ์— ์–ด๋–ป๊ฒŒ ๋„์›€์ด ๋˜๋Š”์ง€ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

Pulumi๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ธํ”„๋ผ๋ฅผ ์ฝ”๋“œ๋กœ ํ…Œ์ŠคํŠธํ•ฉ๋‹ˆ๋‹ค. 1 ๋ถ€

์ธํ”„๋ผ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?

์ž์„ธํžˆ ์„ค๋ช…ํ•˜๊ธฐ ์ „์— "์ธํ”„๋ผ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋Š” ์ด์œ ๋Š” ๋ฌด์—‡์ž…๋‹ˆ๊นŒ?"๋ผ๋Š” ์งˆ๋ฌธ์„ ๋˜์ ธ ๋ณผ ๊ฐ€์น˜๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ด์œ ๊ฐ€ ์žˆ์œผ๋ฉฐ ๊ทธ ์ค‘ ์ผ๋ถ€๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

  • ๊ฐœ๋ณ„ ๊ธฐ๋Šฅ ๋˜๋Š” ํ”„๋กœ๊ทธ๋žจ ๋กœ์ง์˜ ๋‹จํŽธ์— ๋Œ€ํ•œ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ
  • ํŠน์ • ์ œ์•ฝ ์กฐ๊ฑด์— ๋Œ€ํ•ด ์›ํ•˜๋Š” ์ธํ”„๋ผ ์ƒํƒœ๋ฅผ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ์Šคํ† ๋ฆฌ์ง€ ๋ฒ„ํ‚ท์˜ ์•”ํ˜ธํ™” ๋ถ€์กฑ ๋˜๋Š” ์ธํ„ฐ๋„ท์—์„œ ๊ฐ€์ƒ ๋จธ์‹ ์œผ๋กœ์˜ ๋ณดํ˜ธ๋˜์ง€ ์•Š์€ ๊ฐœ๋ฐฉํ˜• ์•ก์„ธ์Šค์™€ ๊ฐ™์€ ์ผ๋ฐ˜์ ์ธ ์˜ค๋ฅ˜๋ฅผ ๊ฐ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • ์ธํ”„๋ผ ํ”„๋กœ๋น„์ €๋‹ ๊ตฌํ˜„์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ํ”„๋กœ๋น„์ €๋‹ ํ›„ ๊ธฐ๋Šฅ์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด "ํ”„๋กœ๊ทธ๋ž˜๋ฐ๋œ" ์ธํ”„๋ผ ๋‚ด์—์„œ ์‹คํ–‰๋˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋กœ์ง์˜ ๋Ÿฐํƒ€์ž„ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•ฉ๋‹ˆ๋‹ค.
  • ๋ณด์‹œ๋‹ค์‹œํ”ผ ๊ด‘๋ฒ”์œ„ํ•œ ์ธํ”„๋ผ ํ…Œ์ŠคํŠธ ์˜ต์…˜์ด ์žˆ์Šต๋‹ˆ๋‹ค. Polumi๋Š” ์ด ์ŠคํŽ™ํŠธ๋Ÿผ์˜ ๋ชจ๋“  ์ง€์ ์—์„œ ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ๊ฐ–์ถ”๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์‹œ์ž‘ํ•˜์—ฌ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

๋‹จ์œ„ ํ…Œ์ŠคํŠธ

Pulumi ํ”„๋กœ๊ทธ๋žจ์€ JavaScript, Python, TypeScript ๋˜๋Š” Go์™€ ๊ฐ™์€ ๋ฒ”์šฉ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋กœ ์ž‘์„ฑ๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ํฌํ•จํ•œ ๋„๊ตฌ์™€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ํฌํ•จํ•˜์—ฌ ์ด๋Ÿฌํ•œ ์–ธ์–ด์˜ ๋ชจ๋“  ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Pulumi๋Š” ๋ฉ€ํ‹ฐ ํด๋ผ์šฐ๋“œ์ด๋ฏ€๋กœ ๋ชจ๋“  ํด๋ผ์šฐ๋“œ ์ œ๊ณต์—…์ฒด์˜ ํ…Œ์ŠคํŠธ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

(์ด ๊ธฐ์‚ฌ์—์„œ๋Š” ๋‹ค๊ตญ์–ด, ๋ฉ€ํ‹ฐํด๋ผ์šฐ๋“œ์ž„์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  JavaScript์™€ Mocha๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  AWS์— ์ค‘์ ์„ ๋‘ก๋‹ˆ๋‹ค. Python์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. unittest, ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ ๋˜๋Š” ์›ํ•˜๋Š” ๋‹ค๋ฅธ ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๋กœ ์ด๋™ํ•˜์„ธ์š”. ๋ฌผ๋ก  Pulumi๋Š” Azure, Google Cloud, Kubernetes์™€๋„ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.)

์ง€๊ธˆ๊นŒ์ง€ ์‚ดํŽด๋ณด์•˜๋“ฏ์ด ์ธํ”„๋ผ ์ฝ”๋“œ๋ฅผ ํ…Œ์ŠคํŠธํ•˜๋ ค๋Š” ๋ฐ์—๋Š” ๋ช‡ ๊ฐ€์ง€ ์ด์œ ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ ์ค‘ ํ•˜๋‚˜๊ฐ€ ๊ธฐ์กด ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ์— CIDR ๊ณ„์‚ฐ, ์ด๋ฆ„, ํƒœ๊ทธ ๋“ฑ์˜ ๋™์ ์ธ ๊ณ„์‚ฐ๊ณผ ๊ฐ™์€ ๊ธฐ๋Šฅ์ด ์žˆ์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. - ์•„๋งˆ ํ…Œ์ŠคํŠธํ•ด๋ณด๊ณ  ์‹ถ์„ ๊ฒ๋‹ˆ๋‹ค. ์ด๋Š” ์„ ํ˜ธํ•˜๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์–ธ์–ด๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•œ ์ผ๋ฐ˜ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
์ข€ ๋” ๋ณต์žกํ•ด์ง€๊ธฐ ์œ„ํ•ด ํ”„๋กœ๊ทธ๋žจ์ด ๋ฆฌ์†Œ์Šค๋ฅผ ํ• ๋‹นํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์„ค๋ช…์„ ์œ„ํ•ด ๊ฐ„๋‹จํ•œ EC2 ์„œ๋ฒ„๋ฅผ ์ƒ์„ฑํ•ด์•ผ ํ•˜๋ฉฐ ๋‹ค์Œ ์‚ฌํ•ญ์„ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค.

  • ์ธ์Šคํ„ด์Šค์—๋Š” ํƒœ๊ทธ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค Name.
  • ์ธ์Šคํ„ด์Šค๋Š” ์ธ๋ผ์ธ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ ๋ฉ๋‹ˆ๋‹ค. userData - AMI(์ด๋ฏธ์ง€)๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์ธํ„ฐ๋„ท์— SSH๊ฐ€ ๋…ธ์ถœ๋˜์–ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.

์ด ์˜ˆ๋Š” ๋‹ค์Œ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•ฉ๋‹ˆ๋‹ค. ๋‚ด ์˜ˆ๋Š” aws-js-webserver:

index.js:

"use strict";
 
let aws = require("@pulumi/aws");
 
let group = new aws.ec2.SecurityGroup("web-secgrp", {
    ingress: [
        { protocol: "tcp", fromPort: 22, toPort: 22, cidrBlocks: ["0.0.0.0/0"] },
        { protocol: "tcp", fromPort: 80, toPort: 80, cidrBlocks: ["0.0.0.0/0"] },
    ],
});
 
let userData =
`#!/bin/bash
echo "Hello, World!" > index.html
nohup python -m SimpleHTTPServer 80 &`;
 
let server = new aws.ec2.Instance("web-server-www", {
    instanceType: "t2.micro",
    securityGroups: [ group.name ], // reference the group object above
    ami: "ami-c55673a0"             // AMI for us-east-2 (Ohio),
    userData: userData              // start a simple web server
});
 
exports.group = group;
exports.server = server;
exports.publicIp = server.publicIp;
exports.publicHostName = server.publicDns;

์ด๊ฒƒ์ด ๊ธฐ๋ณธ Pulumi ํ”„๋กœ๊ทธ๋žจ์ž…๋‹ˆ๋‹ค. ๊ฐ„๋‹จํžˆ EC2 ๋ณด์•ˆ ๊ทธ๋ฃน๊ณผ ์ธ์Šคํ„ด์Šค๋ฅผ ํ• ๋‹นํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์—ฌ๊ธฐ์„œ๋Š” ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ์„ธ ๊ฐ€์ง€ ๊ทœ์น™์„ ๋ชจ๋‘ ์œ„๋ฐ˜ํ•˜๊ณ  ์žˆ๋‹ค๋Š” ์ ์— ์œ ์˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•ด๋ณด์ž!

ํ…Œ์ŠคํŠธ ์ž‘์„ฑ

ํ…Œ์ŠคํŠธ์˜ ์ผ๋ฐ˜์ ์ธ ๊ตฌ์กฐ๋Š” ์ผ๋ฐ˜ Mocha ํ…Œ์ŠคํŠธ์™€ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

ec2tests.js

test.js:
let assert = require("assert");
let mocha = require("mocha");
let pulumi = require("@pulumi/pulumi");
let infra = require("./index");
 
describe("Infrastructure", function() {
    let server = infra.server;
    describe("#server", function() {
        // TODO(check 1): ะ”ะพะปะถะตะฝ ะฑั‹ั‚ัŒ ั‚ัะณ Name.
        // TODO(check 2): ะะต ะดะพะปะถะฝะพ ะฑั‹ั‚ัŒ inline-ัะบั€ะธะฟั‚ะฐ userData.
    });
    let group = infra.group;
    describe("#group", function() {
        // TODO(check 3): ะะต ะดะพะปะถะฝะพ ะฑั‹ั‚ัŒ SSH, ะพั‚ะบั€ั‹ั‚ะพะณะพ ะฒ ะ˜ะฝั‚ะตั€ะฝะตั‚.
    });
});

์ด์ œ ์ฒซ ๋ฒˆ์งธ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ์ธ์Šคํ„ด์Šค์— ํƒœ๊ทธ๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜์„ธ์š”. Name. ์ด๋ฅผ ํ™•์ธํ•˜๋ ค๋ฉด EC2 ์ธ์Šคํ„ด์Šค ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์™€์„œ ํ•ด๋‹น ์†์„ฑ์„ ํ™•์ธํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค. tags:

 // check 1: ะ”ะพะปะถะตะฝ ะฑั‹ั‚ัŒ ั‚ัะณ Name.
        it("must have a name tag", function(done) {
            pulumi.all([server.urn, server.tags]).apply(([urn, tags]) => {
                if (!tags || !tags["Name"]) {
                    done(new Error(`Missing a name tag on server ${urn}`));
                } else {
                    done();
                }
            });
        });

์ผ๋ฐ˜์ ์ธ ํ…Œ์ŠคํŠธ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ์ฃผ๋ชฉํ•  ๋งŒํ•œ ๋ช‡ ๊ฐ€์ง€ ๊ธฐ๋Šฅ์ด ์žˆ์Šต๋‹ˆ๋‹ค.

  • ๋ฐฐํฌํ•˜๊ธฐ ์ „์— ๋ฆฌ์†Œ์Šค ์ƒํƒœ๋ฅผ ์ฟผ๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ…Œ์ŠคํŠธ๋Š” ํ•ญ์ƒ "๊ณ„ํš"(๋˜๋Š” "๋ฏธ๋ฆฌ ๋ณด๊ธฐ") ๋ชจ๋“œ์—์„œ ์‹คํ–‰๋ฉ๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ๊ฐ’์ด ๊ฒ€์ƒ‰๋˜์ง€ ์•Š๊ฑฐ๋‚˜ ์ •์˜๋˜์ง€ ์•Š๋Š” ์†์„ฑ์ด ๋งŽ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ํด๋ผ์šฐ๋“œ ๊ณต๊ธ‰์ž๊ฐ€ ๊ณ„์‚ฐํ•œ ๋ชจ๋“  ์ถœ๋ ฅ ์†์„ฑ์ด ํฌํ•จ๋ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ…Œ์ŠคํŠธ์—์„œ๋Š” ์ •์ƒ์ ์ธ ํ˜„์ƒ์ž…๋‹ˆ๋‹ค. ์ž…๋ ฅ ๋ฐ์ดํ„ฐ๋งŒ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค. ๋‚˜์ค‘์— ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ์— ๊ด€ํ•ด ์ด ๋ฌธ์ œ๋ฅผ ๋‹ค์‹œ ๋‹ค๋ฃจ๊ฒ ์Šต๋‹ˆ๋‹ค.
  • ๋ชจ๋“  Pulumi ๋ฆฌ์†Œ์Šค ์†์„ฑ์€ ์ถœ๋ ฅ์ด๊ณ  ๊ทธ ์ค‘ ๋งŽ์€ ์†์„ฑ์ด ๋น„๋™๊ธฐ์‹์œผ๋กœ ํ‰๊ฐ€๋˜๋ฏ€๋กœ ๊ฐ’์— ์•ก์„ธ์Šคํ•˜๋ ค๋ฉด ์ ์šฉ ๋ฉ”์„œ๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” Promise ๋ฐ afunction๊ณผ ๋งค์šฐ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค. then .
  • ์˜ค๋ฅ˜ ๋ฉ”์‹œ์ง€์— ๋ฆฌ์†Œ์Šค URN์„ ํ‘œ์‹œํ•˜๊ธฐ ์œ„ํ•ด ์—ฌ๋Ÿฌ ์†์„ฑ์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฏ€๋กœ ๋‹ค์Œ ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. pulumi.all๊ทธ๋“ค์„ ๊ฒฐํ•ฉํ•ฉ๋‹ˆ๋‹ค.
  • ๋งˆ์ง€๋ง‰์œผ๋กœ ์ด๋Ÿฌํ•œ ๊ฐ’์€ ๋น„๋™๊ธฐ์ ์œผ๋กœ ๊ณ„์‚ฐ๋˜๋ฏ€๋กœ Mocha์— ๋‚ด์žฅ๋œ ๋น„๋™๊ธฐ ์ฝœ๋ฐฑ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. done ๋˜๋Š” ์•ฝ์†์„ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.

๋ชจ๋“  ์„ค์ •์ด ์™„๋ฃŒ๋˜๋ฉด ๊ฐ„๋‹จํ•œ JavaScript ๊ฐ’์œผ๋กœ ์ž…๋ ฅ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์žฌ์‚ฐ tags ๋Š” ๋งต(์—ฐ๊ด€ ๋ฐฐ์—ด)์ด๋ฏ€๋กœ (1) false๊ฐ€ ์•„๋‹Œ์ง€, (2) ๋‹ค์Œ์— ๋Œ€ํ•œ ํ‚ค๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค. Name. ๋งค์šฐ ๊ฐ„๋‹จํ•˜๋ฏ€๋กœ ์ด์ œ ๋ฌด์—‡์ด๋“  ํ…Œ์ŠคํŠธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

์ด์ œ ๋‘ ๋ฒˆ์งธ ์ˆ˜ํ‘œ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ํ›จ์”ฌ ๋” ๊ฐ„๋‹จํ•ฉ๋‹ˆ๋‹ค.

 // check 2: ะะต ะดะพะปะถะฝะพ ะฑั‹ั‚ัŒ inline-ัะบั€ะธะฟั‚ะฐ userData.
        it("must not use userData (use an AMI instead)", function(done) {
            pulumi.all([server.urn, server.userData]).apply(([urn, userData]) => {
                if (userData) {
                    done(new Error(`Illegal use of userData on server ${urn}`));
                } else {
                    done();
                }
            });
        });

๊ทธ๋ฆฌ๊ณ  ๋งˆ์ง€๋ง‰์œผ๋กœ ์„ธ ๋ฒˆ์งธ ํ…Œ์ŠคํŠธ๋ฅผ ์ž‘์„ฑํ•ด ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋ณด์•ˆ ๊ทธ๋ฃน๊ณผ ๊ด€๋ จ๋œ ๋กœ๊ทธ์ธ ๊ทœ์น™(๋งŽ์„ ์ˆ˜ ์žˆ์Œ)๊ณผ ํ•ด๋‹น ๊ทœ์น™์˜ CIDR ๋ฒ”์œ„(๋งŽ์„ ์ˆ˜๋„ ์žˆ์Œ)๋ฅผ ์ฐพ๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ด๋Š” ์ข€ ๋” ๋ณต์žกํ•ฉ๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๋Š” ๋‹ค์Œ์„ ์ˆ˜ํ–‰ํ–ˆ์Šต๋‹ˆ๋‹ค.

    // check 3: ะะต ะดะพะปะถะฝะพ ะฑั‹ั‚ัŒ SSH, ะพั‚ะบั€ั‹ั‚ะพะณะพ ะฒ ะ˜ะฝั‚ะตั€ะฝะตั‚.
        it("must not open port 22 (SSH) to the Internet", function(done) {
            pulumi.all([ group.urn, group.ingress ]).apply(([ urn, ingress ]) => {
                if (ingress.find(rule =>
                        rule.fromPort == 22 && rule.cidrBlocks.find(block =>
                            block === "0.0.0.0/0"))) {
                    done(new Error(`Illegal SSH port 22 open to the Internet (CIDR 0.0.0.0/0) on group ${urn}`));
                } else {
                    done();
                }
            });
        });

๊ทธ๊ฒŒ ๋‹ค์•ผ. ์ด์ œ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•ด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค!

ํ…Œ์ŠคํŠธ ์‹คํ–‰

๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ์„ ํƒํ•œ ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ผ๋ฐ˜์ ์ธ ๋ฐฉ๋ฒ•์œผ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ ํ’€๋ฃจ๋ฏธ์—๋Š” ์ฃผ๋ชฉํ•  ๋งŒํ•œ ํŠน์ง•์ด ํ•˜๋‚˜ ์žˆ๋‹ค.
์ผ๋ฐ˜์ ์œผ๋กœ Pulumi ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ํ•˜๋ ค๋ฉด ์–ธ์–ด ๋Ÿฐํƒ€์ž„์„ ๊ตฌ์„ฑํ•˜๊ณ  Pulumi ์—”์ง„ ์‹คํ–‰์„ ์ œ์–ดํ•˜์—ฌ ๋ฆฌ์†Œ์Šค ๊ด€๋ จ ์ž‘์—…์„ ๊ธฐ๋กํ•˜๊ณ  ๊ณ„ํš์— ํฌํ•จ์‹œํ‚ค๋Š” pulimi CLI(Command Line Interface)๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ•œ ๊ฐ€์ง€ ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ํ…Œ์ŠคํŠธ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ์ œ์–ด ํ•˜์— ์‹คํ–‰๋˜๋Š” ๊ฒฝ์šฐ CLI์™€ Pulumi ์—”์ง„ ๊ฐ„์—๋Š” ํ†ต์‹ ์ด ์—†์Šต๋‹ˆ๋‹ค.

์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋ฉด ๋‹ค์Œ ์‚ฌํ•ญ์„ ์ง€์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

  • ํ™˜๊ฒฝ ๋ณ€์ˆ˜์— ํฌํ•จ๋œ ํ”„๋กœ์ ํŠธ ์ด๋ฆ„ PULUMI_NODEJS_PROJECT (๋˜๋Š” ๋” ์ผ๋ฐ˜์ ์œผ๋กœ, PULUMI__PROJECT ะดะปั ะดั€ัƒะณะธั… ัะทั‹ะบะพะฒ).
    ํ™˜๊ฒฝ ๋ณ€์ˆ˜์— ์ง€์ •๋œ ์Šคํƒ์˜ ์ด๋ฆ„ PULUMI_NODEJS_STACK (๋˜๋Š” ๋” ์ผ๋ฐ˜์ ์œผ๋กœ, PULUMI__ STACK).
    ์Šคํƒ ๊ตฌ์„ฑ ๋ณ€์ˆ˜. ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. PULUMI_CONFIG ํ•ด๋‹น ํ˜•์‹์€ ํ‚ค/๊ฐ’ ์Œ์ด ์žˆ๋Š” JSON ๋งต์ž…๋‹ˆ๋‹ค.

    ํ”„๋กœ๊ทธ๋žจ์€ ์‹คํ–‰ ์ค‘์— CLI/์—”์ง„์— ๋Œ€ํ•œ ์—ฐ๊ฒฐ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ๊ฒฝ๊ณ ๋ฅผ ํ‘œ์‹œํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ”„๋กœ๊ทธ๋žจ์ด ์‹ค์ œ๋กœ ์•„๋ฌด๊ฒƒ๋„ ๋ฐฐํฌํ•˜์ง€ ์•Š๊ณ  ์˜๋„ํ•œ ๋Œ€๋กœ ๋ฐฐํฌ๋˜์ง€ ์•Š์œผ๋ฉด ๋†€๋ž„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค! Pulumi์—๊ฒŒ ์ด๊ฒƒ์ด ์ •ํ™•ํžˆ ํ•„์š”ํ•œ ๊ฒƒ์ž„์„ ์•Œ๋ฆฌ๋ ค๋ฉด ๋‹ค์Œ์„ ์„ค์น˜ํ•˜์‹ญ์‹œ์˜ค. PULUMI_TEST_MODE ะฒ true.

    ํ”„๋กœ์ ํŠธ ์ด๋ฆ„์„ ์ง€์ •ํ•ด์•ผ ํ•œ๋‹ค๊ณ  ์ƒ์ƒํ•ด ๋ณด์„ธ์š”. my-ws, ์Šคํƒ ์ด๋ฆ„ dev๋ฐ AWS ๋ฆฌ์ „ us-west-2. Mocha ํ…Œ์ŠคํŠธ๋ฅผ ์‹คํ–‰ํ•˜๊ธฐ ์œ„ํ•œ ๋ช…๋ น์ค„์€ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

    $ PULUMI_TEST_MODE=true 
        PULUMI_NODEJS_STACK="my-ws" 
        PULUMI_NODEJS_PROJECT="dev" 
        PULUMI_CONFIG='{ "aws:region": "us-west-2" }' 
        mocha tests.js

    ์˜ˆ์ƒ๋Œ€๋กœ ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ์„ธ ๊ฐ€์ง€ ํ…Œ์ŠคํŠธ์— ์‹คํŒจํ–ˆ์Œ์„ ์•Œ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค!

    Infrastructure
        #server
          1) must have a name tag
     	 2) must not use userData (use an AMI instead)
        #group
          3) must not open port 22 (SSH) to the Internet
    
      0 passing (17ms)
      3 failing
     
     1) Infrastructure
           #server
             must have a name tag:
         Error: Missing a name tag on server
            urn:pulumi:my-ws::my-dev::aws:ec2/instance:Instance::web-server-www
    
     2) Infrastructure
           #server
             must not use userData (use an AMI instead):
         Error: Illegal use of userData on server
            urn:pulumi:my-ws::my-dev::aws:ec2/instance:Instance::web-server-www
    
     3) Infrastructure
           #group
             must not open port 22 (SSH) to the Internet:
         Error: Illegal SSH port 22 open to the Internet (CIDR 0.0.0.0/0) on group

    ํ”„๋กœ๊ทธ๋žจ์„ ์ˆ˜์ •ํ•ด ๋ด…์‹œ๋‹ค:

    "use strict";
     
    let aws = require("@pulumi/aws");
     
    let group = new aws.ec2.SecurityGroup("web-secgrp", {
        ingress: [
            { protocol: "tcp", fromPort: 80, toPort: 80, cidrBlocks: ["0.0.0.0/0"] },
        ],
    });
     
    let server = new aws.ec2.Instance("web-server-www", {
        tags: { "Name": "web-server-www" },
        instanceType: "t2.micro",
        securityGroups: [ group.name ], // reference the group object above
        ami: "ami-c55673a0"             // AMI for us-east-2 (Ohio),
    });
     
    exports.group = group;
    exports.server = server;
    exports.publicIp = server.publicIp;
    exports.publicHostName = server.publicDns;
    

    ๊ทธ๋Ÿฐ ๋‹ค์Œ ํ…Œ์ŠคํŠธ๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

    Infrastructure
        #server
          โœ“ must have a name tag
          โœ“ must not use userData (use an AMI instead)
        #group
          โœ“ must not open port 22 (SSH) to the Internet
     
     
     3 passing (16ms)

    ๋ชจ๋“  ์ผ์ด ์ˆœ์กฐ๋กญ๊ฒŒ ์ง„ํ–‰๋˜์—ˆ์Šต๋‹ˆ๋‹ค... ๋งŒ์„ธ! โœ“โœ“โœ“

    ์˜ค๋Š˜์€ ์—ฌ๊ธฐ๊นŒ์ง€์ž…๋‹ˆ๋‹ค. ๋ฒˆ์—ญ์˜ ๋‘ ๋ฒˆ์งธ ๋ถ€๋ถ„์—์„œ ๋ฐฐํฌ ํ…Œ์ŠคํŠธ์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค ๐Ÿ˜‰

์ถœ์ฒ˜ : habr.com

์ฝ”๋ฉ˜ํŠธ๋ฅผ ์ถ”๊ฐ€