[컴] blogger syntax highlighting

블로거 / 신택스 / 하이라이트 / 문법 / 블로그 / 페이지

blogger syntax highlighting

prismjs 사용

<head>
<link href="https://unpkg.com/prismjs@1.29.0/themes/prism.css" rel="stylesheet" />
<script src="https://unpkg.com/prismjs@1.29.0/components/prism-core.min.js"></script>
<script src="https://unpkg.com/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
...

그러면 page에 아래와 같이 class 가 language-xxx로 되어 있는 것들에 대해서 highlighting 된다.

<pre><code class="language-css">p { color: red }</code></pre>

지원하는 언어는 다음 링크에서 확인할 수 있다.

[컴][웹] vue3 설치, build, 그리고 multi page app

vuejs 3 / vuejs3 / 여러 페이지 / 여러 entry

vue3 설치, build, 그리고 multi page app

Prerequisites

  1. npm

설치

  1. npm init vue@latest
d:\a\prog\myproj-test>npm init vue@latest

Vue.js - The Progressive JavaScript Framework

√ Project name: ... myproj
√ Add TypeScript? ... No / Yes
√ Add JSX Support? ... No / Yes
√ Add Vue Router for Single Page Application development? ... No / Yes
√ Add Pinia for state management? ... No / Yes
√ Add Vitest for Unit Testing? ... No / Yes
√ Add an End-to-End Testing Solution? » Cypress
√ Add ESLint for code quality? ... No / Yes
√ Add Prettier for code formatting? ... No / Yes

Scaffolding project in d:\a\prog\myproj-test\myproj...

Done. Now run:

  cd myproj
  npm install
  npm run format
  npm run dev


d:\a\prog\myproj-test>

vue3 에서 vite 로 build 할 때 import error

d:\a\prog\myproj-test>npm run build

> chips@0.0.0 build
> vite build

failed to load config from d:\a\prog\myproj-test\vite.config.js
error during build:
d:\a\prog\myproj-test\vite.config.js:1
import { fileURLToPath, URL } from 'node:url'
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at Object.compileFunction (node:vm:360:18)
    at wrapSafe (node:internal/modules/cjs/loader:1088:15)
    at Module._compile (node:internal/modules/cjs/loader:1123:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1213:10)
    at _require.extensions.<computed> [as .js] (file:///d:/a/prog/myproj-test/node_modules/vite/dist/node/chunks/dep-24daf00c.js:64459:17)
    at Module.load (node:internal/modules/cjs/loader:1037:32)
    at Module._load (node:internal/modules/cjs/loader:878:12)
    at Module.require (node:internal/modules/cjs/loader:1061:19)
    at require (node:internal/modules/cjs/helpers:103:18)
    at loadConfigFromBundledFile (file:///d:/a/prog/myproj-test/node_modules/vite/dist/node/chunks/dep-24daf00c.js:64464:21)

위와 같은 error 가 발생할 때 다음 2가지 방법이 있다.

  1. vite.config.js의 이름을 vite.config.mjs로 변경 .cjs는 nodejs 가 CommonJS module 로 인식하고 .mjs 는 ECMAScript module 로 인식한다. 기본적으로 package.json"type": "module" 이 없다면 CommonJS 로 인식한다.

  2. package.json"type": "module" 을 추가(이것은 node version 13 이상에서 가능)

    // package.json
    {
      ...
      "type": "module",
      ...
    }
d:\a\prog\myproj-test>npm run build

> chips@0.0.0 build
> vite build

vite v4.3.1 building for production...
✓ 38 modules transformed.
dist/assets/logo-277e0e97.svg    0.28 kB │ gzip:  0.20 kB
dist/index.html                  0.42 kB │ gzip:  0.28 kB
dist/assets/index-1da8cd0c.css   3.68 kB │ gzip:  1.20 kB
dist/assets/index-baba5e49.js   63.89 kB │ gzip: 25.32 kB
✓ built in 1.05s

여러 페이지 만들기

import { fileURLToPath, URL } from 'node:url'

import { resolve } from 'path'
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  build: {
    rollupOptions: {
      // https://vitejs.dev/guide/build.html#multi-page-app
      input: {
        main: resolve(__dirname, 'entry/main/index.html'),
        test: resolve(__dirname, 'entry/test/index.html'),
      },
      output: {
        // https://rollupjs.org/configuration-options/#output-dir
        dir: 'dist' // if you want to change the dist folder name
      }
    },
  },
})

vite-plugin-virtual-mpa

Reference

  1. Tooling | Vue.js
  2. vue.js - How to build a multi pages application by vite2 and vue3? - Stack Overflow
  3. Building for Production | Vite

[컴] Terraformer 사용법

테라폼 / 테라포머 / .tsstate file 을 만드는 법

Terraformer

google 이 인수한 Waze 라는 회사의 SRE 팀에서 만든 tool

설치방법

windows

  1. terraform 설치
  2. https://github.com/GoogleCloudPlatform/terraformer/releases 에서 terraformer download
  3. 작업하려는 folder로 가서, 아래처럼 versions.tf를 만들고, terraform init 을 한다. 그러면 terraform 의 plugin 이 설치된다.
# versions.tf
#
# ref: https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-build
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }

  required_version = ">= 1.2.0"
}

aws resource 들의 이름은 다음 링크에서 확인하면 된다.

rem 특정 iam 에 대한 모든 정보를 가져올때

terraformer import aws --resources="iam"
rem 특정 iam 외의 모든 정보를 가져올때

terraformer import aws --resources="*" --exclude="iam"
rem 특정 sg, vpc 에 대한 정보를 가져올때

terraformer import aws -r sg,vpc --filter Type=sg;Name=vpc_id;Value=VPC_ID --filter Type=vpc;Name=id;Value=VPC_ID
rem  tags.Name 이 my-test-instance 인 instance 정보를 가져올때

terraformer import aws --resources=ec2_instance --filter Name=tags.Name;Value=my-test-instance --regions=ap-northeast-2

tags.Name 이 my-rds 인 RDS 정보를 가져올때, 아래처럼 filter 에 id 가 my-rds만 가져오게 하면, 관련된 parameter group 을 가져오지 못하게 된다.

rem  tags.Name 이 my-rds 인 RDS 정보를 가져올때

terraformer import aws --resources=rds --filter="Name=id;Value=my-rds" --regions=ap-northeast-2

terraformer import aws --resources=rds --regions=ap-northeast-2
rem  tags.Name 이 my-lb 인 load balancer 정보를 가져올때

terraformer import aws --resources=alb --filter Name=tags.Name;Value=my-lb;Type=application

[컴] java 의 dynamic proxy 예시

 

프록시 / 설명 /

java 의 dynamic proxy 예시

만약 우리가 Test 라는 class를 가지고 있고, 이 class 의 return 값을 변경하고 싶을 수 있다. 그런데 이 class 는 3rd party library 라서 우리가 수정할 수 없다고 하자. 이때 우리가 해볼 수 있는 방식은 다음과 같을 것이다. 다른 좋은 방법은 떠오르지 않는다.

  1. 이럴 때 우리는 dynamic proxy 를 호출하는 다른 class 를 만들고, 그것을 대신 사용하게 할 수 있다. 다만 이때는 다른 public method 도 다 만들어줘야 할 것이다.
  2. Test 를 extend 해서 특정 method 만 override 한다. 이것은 3rd party 에서 열어놨다면 가능하다.
  3. 여기에 Proxy 로 작업하는 것이 들어간다. dynamic proxy

여기서는 위 방법중 3번째 방법을 한 번 살펴보자.

아래코드로 우리는 ITest 에 대한 wrapper class 를 만들 수 있게 됐다. 그럼 이제 원래 Test class 대신에 Proxy 를 사용하도록 하면 된다. 그러면 이제 InvocationHandler.invoke 가 대신 호출 될 것이다.

// Application.kt
package com.example.demo

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import java.lang.reflect.InvocationHandler
import java.lang.reflect.Method
import java.lang.reflect.Proxy


fun main(args: Array<String>) {
    val myTestInvocationHandler = DynamicInvocationHandler()
    val test = Proxy.newProxyInstance(Test::class.java.classLoader, arrayOf(ITest::class.java), myTestInvocationHandler) as ITest

    System.out.println(test.testIt())   // 5 가 출력

    val rtest = Test()
    System.out.println(rtest.testIt())  // 11 이 출력

}


internal class DynamicInvocationHandler : InvocationHandler {
    override fun invoke(proxy: Any?, method: Method, args: Array<Any?>?): Any? {
        return if ("testIt" == method.getName()) {
            5
        } else null
    }
}


internal interface ITest {
    fun testIt(): Int
}


internal class Test : ITest {
    override fun testIt(): Int {
        return 11
    }
}

[컴] Spring framework 의 @Pointcut의 동작

스프링 /

Spring framework 의 @Pointcut의 동작

ref.1 , ref.2 를 보자.

아래 예시는 모든 transfer 라는 이름의 method 가 실행될때라는 point(@Pointcut) 를 잡는 것이다. 함수이름 anyOldTransfer 는 그저 pointcut 의 이름을 정하는 역할을 할 뿐이다. 즉 anyOldTransfer라는 이름의 pointcut 이라고 보면 된다.

이 pointcut 을 기점으로 이 이후에, 또는 이 이전에 무엇인가를 하도록 정의할 수 있다.

@Pointcut("execution(* transfer(..))")// the pointcut expression
private void anyOldTransfer() {}// the pointcut signature
..
@AfterReturning(value = "anyOldTransfer()", returning = "id")
fun doSomething(joinPoint: JoinPoint, id: Long) {
...

조금더 자세한 이야기는 ref.1 에 있다.

dynamic proxy over reflection

정리가 필요...
answers from phind.com :

Java dynamic proxies provide a way to create proxy objects that implement a list of interfaces specified at runtime. These proxy objects can be used to add or modify the functionality of an existing class without modifying its original code. Dynamic proxies are particularly useful for framework writers and when concrete class implementations are not known until runtime Source 0.

The primary advantage of dynamic proxies over reflection is that dynamic proxies provide a type-safe way to perform method invocation on objects that present interface APIs Source 2. With reflection, you may need to manually check for method existence and handle exceptions related to incorrect method names or argument types.

Here are some pros and cons of using dynamic proxies versus reflection:

Dynamic Proxies:

Pros:

  • Type-safe method invocation, which reduces the chance of runtime errors due to incorrect method names or argument types Source 2.
  • Easier to implement handlers for multiple interfaces and methods, as all method invocations are routed to a single invoke() method Source 0.

Cons:

  • Limited to proxying interfaces, not concrete classes Source 3.
  • Requires the implementation of an InvocationHandler and the use of the Proxy class, which may be more complex than simply using reflection Source 3.

Reflection:

Pros:

  • Can be used to access and modify private members of a class, which is not possible with dynamic proxies Source 2.
  • Can be used to create instances of concrete classes, not just interfaces Source 3.

Cons:

  • Not type-safe, which can lead to runtime errors due to incorrect method names or argument types Source 2.
  • Handling multiple interfaces and methods may require additional complexity compared to dynamic proxies Source 0.

In summary, dynamic proxies are a useful tool for implementing proxy objects and adding or modifying functionality of existing classes without modifying their original code. They provide type-safety and can handle multiple interfaces and methods with ease. However, they are limited to proxying interfaces and require the implementation of an InvocationHandler. Reflection, on the other hand, can be used to access and modify private members and create instances of concrete classes, but lacks type-safety and may require additional complexity for handling multiple interfaces and methods.

Reference

  1. 11. Aspect Oriented Programming with Spring
  2. Spring AOP: What’s the difference between JoinPoint and PointCut? - Stack Overflow
  3. Creating Dynamic Proxies with Kotlin Coroutines - Technical Tutorial
  4. How to explicitly invoke default method from a dynamic proxy in Java? - StackTuts 

[컴] Terraform 사용법

helloworld / hell world / 테라폼 예시 / 예제 / 간단 예시

Terraform 사용법

prerequisite

  1. AWS CLI 가 설치돼야 한다.
  2. AWS secret key 도 설정돼야 한다.
  3. terraform

기본적으로 .tffile 을 수정하고, terraform apply 를 하면 infra 에 반영된다. terraform apply을 하면, 일단 변경사항이 어떤 것들인지 보여주고, 적용할 것인지를 묻는다. 그 때 yes 를 하면 실제 적용이 이뤄진다.

  1. 다음처럼 main.tf를 하나 만들고,
  2. terraform init 을 한다.
    • 다음 내용들이 만들어진다.
      • .terraform.lock.hcl : lock file, provider version 들이 적혀있다.
      • .terraform/ : download 해서 install 한 provider 가 들어가 있다.(.exe file)
  3. terraform fmt : formatting 을 해준다. format 에 변경이 있는 file 이름만 stdout 으로 보인다.
  4. terraform validate : 문법확인
  5. terraform apply : code를 보고, 실제 infra 를 생성해준다.
    • terraform.tfstatae file
      • 그러면 이 때 생기는 instance 정보를 다시 가져와서 terraform.tfstataefile에 넣어준다.
      • terraform 은 현재 instance 의 정보를 이 state file(terraform.tfstatae) 로 판단하기 때문에 aws web console 로 변경하면 이 state file 이 out-of-sync 가 된다.
      • 그리고 보안도 중요하다. 그래서 이 파일(terraform.tfstatae)에 대한 접근은 제한적인 사람만 access 할 수 있게 해야 한다.
      • terraform show 를 하면 이 파일의 내용을 보여준다.
  6. terraform state list : 이것을 하면 terraform state file 에 있는 resource 의 list 를 보여준다.
  7. terraform destroy : 만들어 놓은 infra 를 삭제한다. dependency 가 있으면, 그에 맞는 순서대로 terraform 이 삭제해 준다.
  8. terraform output : .tf에서 output 으로 정의한 것들을 보여주게 된다.
# main.tf
# ref: https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-build
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }

  required_version = ">= 1.2.0"
}

provider "aws" {
  region  = "ap-northeast-2"
}

resource "aws_instance" "myserverid1" {
  ami           = "ami-055437ee4dcf92427"
  instance_type = "t2.micro"

  tags = {
    Name = "my-instance-name-namh"
  }
}

# 이 부분을 따로 variable.tf 등으로 만들어도 상관없다. 동작은 같다.
variable "instance_name" {
  description = "Value of the Name tag for the EC2 instance"
  type        = string
  default     = "my-instance-name-namh"
}

# 이 부분을 따로 output.tf 등으로 만들어도 상관없다. 동작은 같다.
output "instance_id" {
  description = "ID of the EC2 instance"
  value       = aws_instance.namh-test.id
}
d:\a\terrform\test>terraform fmt
hello.tf

d:\a\terrform\test>terraform validate
Success! The configuration is valid.

terraform 에서 infra 변경

만약 위 main.tf 에서 ami 부분을 변경하면, terraform 은 현재 떠 있는 instance 에서 ami 를 변경할 수 없기 때문에 기존의 것을 삭제 하고 새로운 ami 로 instance 를 만들게 된다.

resource "aws_instance" "myserverid1" {
  ami           = "ami-0676d41f079015f32"
  instance_type = "t2.micro"
d:\a\terrform\test>terraform apply
aws_instance.namh-test: Refreshing state... [id=i-05b38172e99a351bd]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # aws_instance.namh-test must be replaced
-/+ resource "aws_instance" "namh-test" {
      ~ ami                                  = "ami-055437ee4dcf92427" -> "ami-0676d41f079015f32" # forces replacement
      ~ arn                                  = "arn:aws:ec2:ap-northeast-2:786531771744:instance/i-05b38172e99a351bd" -> (known after apply)
      ~ associate_public_ip_address          = true -> (known after apply)
      ~ availability_zone                    = "ap-northeast-2a" -> (known after apply)
      ~ cpu_core_count                       = 1 -> (known after apply)
      ~ cpu_threads_per_core                 = 1 -> (known after apply)
      ~ disable_api_stop                     = false -> (known after apply)
      ~ disable_api_termination              = false -> (known after apply)
      ~ ebs_optimized                        = false -> (known after apply)
      - hibernation                          = false -> null
      + host_id                              = (known after apply)
      + host_resource_group_arn              = (known after apply)
      + iam_instance_profile                 = (known after apply)
      ~ id                                   = "i-05b38172e99a351bd" -> (known after apply)
      ~ instance_initiated_shutdown_behavior = "stop" -> (known after apply)
      ~ instance_state                       = "running" -> (known after apply)
      ~ ipv6_address_count                   = 0 -> (known after apply)
      ~ ipv6_addresses                       = [] -> (known after apply)
      + key_name                             = (known after apply)
      ~ monitoring                           = false -> (known after apply)
      + outpost_arn                          = (known after apply)
      + password_data                        = (known after apply)
      + placement_group                      = (known after apply)
      ~ placement_partition_number           = 0 -> (known after apply)
      ~ primary_network_interface_id         = "eni-0024d58ca1afb689e" -> (known after apply)
      ~ private_dns                          = "ip-172-31-6-77.ap-northeast-2.compute.internal" -> (known after apply)
      ~ private_ip                           = "172.31.6.77" -> (known after apply)
      ~ public_dns                           = "ec2-52-78-198-216.ap-northeast-2.compute.amazonaws.com" -> (known after apply)
      ~ public_ip                            = "52.78.198.216" -> (known after apply)
      ~ secondary_private_ips                = [] -> (known after apply)
      ~ security_groups                      = [
          - "default",
        ] -> (known after apply)
      ~ subnet_id                            = "subnet-d1f1b0b8" -> (known after apply)
      ~ tags                                 = {
          ~ "Name" = "ExampleAppServerInstance" -> "namh-test"
        }
      ~ tags_all                             = {
          ~ "Name" = "ExampleAppServerInstance" -> "namh-test"
        }
      ~ tenancy                              = "default" -> (known after apply)
      + user_data                            = (known after apply)
      + user_data_base64                     = (known after apply)
      ~ vpc_security_group_ids               = [
          - "sg-14baa97d",
        ] -> (known after apply)
        # (4 unchanged attributes hidden)

      ~ capacity_reservation_specification {
          ~ capacity_reservation_preference = "open" -> (known after apply)

          + capacity_reservation_target {
              + capacity_reservation_id                 = (known after apply)
              + capacity_reservation_resource_group_arn = (known after apply)
            }
        }

      - credit_specification {
          - cpu_credits = "unlimited" -> null
        }

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + kms_key_id            = (known after apply)
          + snapshot_id           = (known after apply)
          + tags                  = (known after apply)
          + throughput            = (known after apply)
          + volume_id             = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      ~ enclave_options {
          ~ enabled = false -> (known after apply)
        }

      + ephemeral_block_device {
          + device_name  = (known after apply)
          + no_device    = (known after apply)
          + virtual_name = (known after apply)
        }

      ~ maintenance_options {
          ~ auto_recovery = "default" -> (known after apply)
        }

      ~ metadata_options {
          ~ http_endpoint               = "enabled" -> (known after apply)
          ~ http_put_response_hop_limit = 1 -> (known after apply)
          ~ http_tokens                 = "optional" -> (known after apply)
          ~ instance_metadata_tags      = "disabled" -> (known after apply)
        }

      + network_interface {
          + delete_on_termination = (known after apply)
          + device_index          = (known after apply)
          + network_card_index    = (known after apply)
          + network_interface_id  = (known after apply)
        }

      ~ private_dns_name_options {
          ~ enable_resource_name_dns_a_record    = false -> (known after apply)
          ~ enable_resource_name_dns_aaaa_record = false -> (known after apply)
          ~ hostname_type                        = "ip-name" -> (known after apply)
        }

      ~ root_block_device {
          ~ delete_on_termination = true -> (known after apply)
          ~ device_name           = "/dev/xvda" -> (known after apply)
          ~ encrypted             = false -> (known after apply)
          ~ iops                  = 100 -> (known after apply)
          + kms_key_id            = (known after apply)
          ~ tags                  = {} -> (known after apply)
          ~ throughput            = 0 -> (known after apply)
          ~ volume_id             = "vol-0e01fc659049ed2d4" -> (known after apply)
          ~ volume_size           = 8 -> (known after apply)
          ~ volume_type           = "gp2" -> (known after apply)
        }
    }

Plan: 1 to add, 0 to change, 1 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_instance.namh-test: Destroying... [id=i-05b38172e99a351bd]
aws_instance.namh-test: Still destroying... [id=i-05b38172e99a351bd, 10s elapsed]
aws_instance.namh-test: Still destroying... [id=i-05b38172e99a351bd, 20s elapsed]
aws_instance.namh-test: Destruction complete after 30s
aws_instance.namh-test: Creating...
aws_instance.namh-test: Still creating... [10s elapsed]
aws_instance.namh-test: Still creating... [20s elapsed]
aws_instance.namh-test: Still creating... [30s elapsed]
aws_instance.namh-test: Creation complete after 31s [id=i-0ff6c6e6655dec3bc]

Apply complete! Resources: 1 added, 0 changed, 1 destroyed.

terraform destroy

d:\a\terrform\test>terraform destroy
aws_instance.namh-test: Refreshing state... [id=i-0ff6c6e6655dec3bc]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
  - destroy

Terraform will perform the following actions:

  # aws_instance.namh-test will be destroyed
  - resource "aws_instance" "namh-test" {
      - ami                                  = "ami-0676d41f079015f32" -> null
      - arn                                  = "arn:aws:ec2:ap-northeast-2:786531771744:instance/i-0ff6c6e6655dec3bc" -> null
      - associate_public_ip_address          = true -> null
      - availability_zone                    = "ap-northeast-2a" -> null
      - cpu_core_count                       = 1 -> null
      - cpu_threads_per_core                 = 1 -> null
      - disable_api_stop                     = false -> null
      - disable_api_termination              = false -> null
      - ebs_optimized                        = false -> null
      - get_password_data                    = false -> null
      - hibernation                          = false -> null
      - id                                   = "i-0ff6c6e6655dec3bc" -> null
      - instance_initiated_shutdown_behavior = "stop" -> null
      - instance_state                       = "running" -> null
      - instance_type                        = "t2.micro" -> null
      - ipv6_address_count                   = 0 -> null
      - ipv6_addresses                       = [] -> null
      - monitoring                           = false -> null
      - placement_partition_number           = 0 -> null
      - primary_network_interface_id         = "eni-0ebdd0e3153dba51d" -> null
      - private_dns                          = "ip-172-31-5-167.ap-northeast-2.compute.internal" -> null
      - private_ip                           = "172.31.5.167" -> null
      - public_dns                           = "ec2-3-35-50-89.ap-northeast-2.compute.amazonaws.com" -> null
      - public_ip                            = "3.35.50.89" -> null
      - secondary_private_ips                = [] -> null
      - security_groups                      = [
          - "default",
        ] -> null
      - source_dest_check                    = true -> null
      - subnet_id                            = "subnet-d1f1b0b8" -> null
      - tags                                 = {
          - "Name" = "namh-test"
        } -> null
      - tags_all                             = {
          - "Name" = "namh-test"
        } -> null
      - tenancy                              = "default" -> null
      - user_data_replace_on_change          = false -> null
      - vpc_security_group_ids               = [
          - "sg-14baa97d",
        ] -> null

      - capacity_reservation_specification {
          - capacity_reservation_preference = "open" -> null
        }

      - credit_specification {
          - cpu_credits = "unlimited" -> null
        }

      - enclave_options {
          - enabled = false -> null
        }

      - maintenance_options {
          - auto_recovery = "default" -> null
        }

      - metadata_options {
          - http_endpoint               = "enabled" -> null
          - http_put_response_hop_limit = 2 -> null
          - http_tokens                 = "required" -> null
          - instance_metadata_tags      = "disabled" -> null
        }

      - private_dns_name_options {
          - enable_resource_name_dns_a_record    = false -> null
          - enable_resource_name_dns_aaaa_record = false -> null
          - hostname_type                        = "ip-name" -> null
        }

      - root_block_device {
          - delete_on_termination = true -> null
          - device_name           = "/dev/xvda" -> null
          - encrypted             = false -> null
          - iops                  = 3000 -> null
          - tags                  = {} -> null
          - throughput            = 125 -> null
          - volume_id             = "vol-0198723c2720811de" -> null
          - volume_size           = 8 -> null
          - volume_type           = "gp3" -> null
        }
    }

Plan: 0 to add, 0 to change, 1 to destroy.

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

aws_instance.namh-test: Destroying... [id=i-0ff6c6e6655dec3bc]
aws_instance.namh-test: Still destroying... [id=i-0ff6c6e6655dec3bc, 10s elapsed]
aws_instance.namh-test: Still destroying... [id=i-0ff6c6e6655dec3bc, 20s elapsed]
aws_instance.namh-test: Destruction complete after 30s

Destroy complete! Resources: 1 destroyed.

terraform output

d:\a\prog\terrform\test>terraform output
╷
│ Warning: No outputs found
│
│ The state file either has no outputs defined, or all the defined outputs are empty. Please define an output in your
│ configuration with the `output` keyword and run `terraform refresh` for it to become available. If you are using
│ interpolation, please verify the interpolated value is not empty. You can use the `terraform console` command to
│ assist.
╵

d:\a\prog\terrform\test>terraform apply
aws_instance.namh-test: Refreshing state... [id=i-0f9248e0f31df356f]

Changes to Outputs:
  + instance_id = "i-0f9248e0f31df356f"

You can apply this plan to save these new output values to the Terraform state, without changing any real
infrastructure.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes


Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

instance_id = "i-0f9248e0f31df356f"

d:\a\prog\terrform\test>terraform output
instance_id = "i-0f9248e0f31df356f"

기본 rds 생성하는 예제

rds 생성하는 terraform이다. 이것은 기존에 존재하는 security group 등을 사용했다.

# ref: https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-build
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }

  required_version = ">= 1.2.0"
}

provider "aws" {
  region = var.region
}


data "aws_availability_zones" "available" {}

resource "aws_db_parameter_group" "myproj" {
  name   = "myproj"
  family = "mariadb10.6"

  # parameter {
  #   name  = "log_connections"
  #   value = "1"
  # }
}

resource "aws_db_instance" "myproj-1" {
  identifier        = "myproj-1"
  instance_class    = "db.t3.micro"
  allocated_storage = 5
  engine            = "MariaDB"
  engine_version    = "10.6.12"
  username          = "myusername"
  password          = var.db_password
  # my-group-prod
  # https://ap-northeast-2.console.aws.amazon.com/rds/home?region=ap-northeast-2#db-subnet-group:id=my-group-prod
  db_subnet_group_name = "my-group-prod"
  vpc_security_group_ids = [
    "sg-0a0a0a0a0a0a0a0aa", # my security group 1
    "sg-0b0b0b0b0b0b0b0b"   # my security group 2
  ]
  # https://ap-northeast-2.console.aws.amazon.com/rds/home?region=ap-northeast-2#parameter-groups-detail:ids=mariadb-10-6-v220825;type=DbParameterGroup;editing=false
  parameter_group_name = "mariadb-10-6-v220825"
  publicly_accessible  = true
  skip_final_snapshot  = true
}


# ----------------------------------------
# variable
# ----------------------------------------

variable "region" {
  default     = "ap-northeast-2"
  description = "AWS region"
}

variable "db_password" {
  description = "RDS root user password"
  sensitive   = true
}

# ----------------------------------------
# output
# ----------------------------------------

output "rds_hostname" {
  description = "RDS instance hostname"
  value       = aws_db_instance.myproj-1.address
  sensitive   = true
}

output "rds_port" {
  description = "RDS instance port"
  value       = aws_db_instance.myproj-1.port
  sensitive   = true
}

output "rds_username" {
  description = "RDS instance root username"
  value       = aws_db_instance.myproj-1.username
  sensitive   = true
}

state 가 다른 방법으로 변경되었을 때 다시 state 를 맞추는 법

terraform plan -refresh-only

terraform 으로 만든후, web console로 변경하면, state 의 sync가 달라지게 된다. 그 때 다시 state 를 sync 하는 방법이다.

terraform plan -refresh-only 를 해서 변경되는 state 가 마음에 들면, terraform apply -refresh-only 를 하면 state file 내용이 변경된다. 이 때 infrastructure 를 적은 .tf 파일 내용은 변경되지 않는다.

terraform plan -refresh-only
terraform apply -refresh-only

terraform state mv

예시:

resource stage_b 를 stage_c 로 이름 변경하는 경우

resource "aws_instance" "stage_b" {
  ...
}
resource "aws_instance" "stage_c" {
  ...
}
terraform state mv aws_instance.stage_b aws_instance.stage_c

moved

stage_bstage_c로 변경한 경우 아래 처럼 써주고, terraform apply 를 해주면 된다. apply 를 하고나선 moved는 삭제되어도 된다.

resource "aws_instance" "stage_c" {
  ...
}

moved {
  from = aws_instance.stage_b
  to   = aws_instance.stage_c
}

만약 .tfstate 파일이 없을때.

만약 infra 가 존재하고 있고, .tfstate 가 없다면, 어떻게 해야 하는가?

이 때는 terraformer 를 사용하도록 하자. 개인적인 경험으로는, terraform import 를 이용하는 것이 낫다.

terraform import

먼저 terraform 에 import 할 내용을 일부 적는다. 그리고 import 를 하면 된다.

아래는 ec2 예시다. ec2 에서는 id 를 사용하고, 다른 곳에서는 id 외의 것을 사용할 수도 있다.

팁: 일단 그냥 시도해봐도 된다. 존재하지 않으면, 존재하지 않는다는 error 가 뜬다. AWS console 의 description 부분을 보면 된다. 그리고 terraformer 을 이용해도 id를 얻을 수 있다.

팁2: terraform console 을 이용하면, import 한 값들을 확인할 수 있다.

resource "aws_instance" "example" {
  # ...instance configuration...
}
terraform import aws_instance.example i-abcd1234

terraform 과 infra 의 연결을 끊으려면(detach)

cloud 에 있는 service 는 그대로 두고, terraform 의 resource 를 지우는 방법.

terraform state 에서 지우면 된다.

terraform state list
terraform state rm <name>

terraform.tfstate 를 s3 에 저장하는 법

# ref: https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-build
terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.16"
    }
  }

  required_version = ">= 1.2.0"
  backend "s3" {
    bucket = "mys3bucket-name"
    key    = "global/ex/myapp/terraform.tfstate"
    region = "ap-northeast-2"
  }
}

instance 를 생성후 bash script 실행하는 법

resource "aws_instance" "linux_instance" {
  ...
  provisioner "file" {
    source      = "./mysetup.sh"      # local 에서의 bash script 위치
    destination = "/tmp/mysetup.sh"   # aws 에서의 위치
  }

  provisioner "remote-exec" {
    inline = [
      "chmod +x /tmp/mysetup.sh",  # 권한 변경
      "sudo /tmp/mysetup.sh",      # 실행
    ]
  }
  # Login to the ec2-user with the aws key.
  connection {
    type        = "ssh"
    user        = "ec2-user"
    password    = ""
    private_key = file(var.keyPath)
    host        = self.public_ip
  }
}

global variable 을 사용하는 법

AWS관련 다른 예시들

See Also

  1. 쿠…sal: [컴] terraform
  2. 쿠...sal: [컴] terraform 에서 ebs block 을 추가하고, user_data 사용하는 예시

[컴][머신러닝] AI 에서 autoencoder

 

머신러닝 / 오토인코더

AI 에서 autoencoder

autoencoder 의 목적은 network를 training을 통해서 높은 차원의 data를 좀 더 낮은 차원을 이용해서 표현(lower dimensinal representation)하는 것이다. 일반적으로 차원수를 낮추는 것이다.[ref. 1]

이 ‘lower dimensinal representation’ 을 encoding이라고도 하고, latent space라고도 한다.

encoder 를 해서 좀 더 낮은 차원을 이용해서 표현(lower dimensinal representation)하게 된다. 예를 들면, 3차원으로 표시된 점들을 2차원에 표시하는 것을 들 수 있다. 여러가지 방법이 있겠지만, 예를 들면, 3차원의 점 (1,2,3) 이 있다고 하면, 이것을 (1,2*3000000) 등으로 표현할 수 있다. 물론 겹치지 않도록 잘 조절해야겠지만.

여하튼, 이렇게 만들어진 값을 encoding 된 값으로 보고, 이런 값들의 집합이 latent space 가 된다. 그러면 여기서 시작해서 새로운 값을 만들어내게 되는데, 이것을 decoding 이라고 이야기 한다.

이것은 diffusion model 에서 이미지를 뭉갰다가 다시 거기서 새로운 이미지를 만들어내는 것을 생각해보면, 이해가 될 듯 하다.

3가지 부분

autoencoder 는 3가지 부분으로 구성된다.

  1. Encoder
    input data를 압축해서 인코딩된 표현으로(encoded representation)으로 만들어주는 모듈
  2. Bottleneck
    encoder에 의해 압축된 정보들을 가지고 있는 모듈이다.
  3. Decoder
    압축된 정보들을 다시 decompress 하고 데이터를 새롭게 구성한다.

References

  1. Autoencoders in Deep Learning: Tutorial & Use Cases [2023]