https://www.acmicpc.net/problem/9252

소요 시간: 20분
메모리: 16048KB
시간: 96ms

🔥 문제

LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다. 예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.

 

입력

첫째 줄과 둘째 줄에 두 문자열이 주어진다. 문자열은 알파벳 대문자로만 이루어져 있으며, 최대 1000글자로 이루어져 있다.

 

출력

첫째 줄에 입력으로 주어진 두 문자열의 LCS의 길이를, 둘째 줄에 LCS를 출력한다.

LCS가 여러 가지인 경우에는 아무거나 출력하고, LCS의 길이가 0인 경우에는 둘째 줄을 출력하지 않는다.

 

 


🍀 풀이

 

BOJ.9251 LCS 문제를 풀이하면서 LCS에 대해 알아본 적이 있다.

 

저번 문제는 LCS의 길이를 출력하는 문제였다면, 이번은 LCS의 길이와 함께 LCS를 출력해야하는 문제이다.

LCS의 길이는 저번에 풀이를 했으니 LCS를 출력하는 방법에 대해서 풀이를 하려고 한다.

 

LCS를 구하는 식을 보자면..

두 문자(A[a]와 B[b])가 같은 경우, lcs[a+1][b+1] = lcs[a][b]+1이고

두 문자가 다른 경우, lcs[a+1][b+1] = Math.max(lcs[a][b+1], lcs[a+1][b])였다.

 

두 문자가 같은 경우 lcs[a][b] 값에서 1을 더하기 때문에 lcs[a+1][b+1]값이 lcs[a][b+1]과 lcs[a+1][b] 값보다 크다는 것을 알 수 있다.

 

두 문자가 다른 경우는 lcs[a+1][b+1]값이 lcs[a][b+1]과 lcs[a+1][b] 중 큰 값이 들어 있을 것이다.

 

 

LCS를 구하기 위해서 거꾸로 올라가는 것을 선택했다.

 

lcs[a][b]가 lcs[a-1][b]과 lcs[a][b-1] 중 하나와 같은 경우는 A[a-1]와 B[b-1] 문자는 같지 않다는 의미이다. 그러므로 lcs[a-1][b]과 lcs[a][b-1] 중 같은 곳으로 이동한다.("LCS가 여러 가지인 경우에는 아무거나 출력"이라는 조건이 있으므로 어디를 가도 상관없다.)

 

lcs[a][b]가 lcs[a-1][b]과 lcs[a][b-1] 모두 다른 경우는 A[a-1]와 B[b-1] 문자가 같다는 의미이다. 그러므로 A[a-1]를 StringBuilder객체 sb에 저장하고 lcs[a-1][b-1]로 이동한다.

 

그리고 이동한 곳이 0인 경우 LCS를 모두 찾았으므로 찾기를 종료하고, sb를 반대로 뒤집어서 출력한다. 

 

1. 문자열 A와 B를 입력받고, 문자 배열로 저장한다.
2. int형 2차원 배열 lcs_arr를 정의한다.
3. 문자열 B와 문자열 A를 2중 for문을 사용하여 모든 문자끼리 비교할 수 있도록 한다.
        1. A[a-1]와 B[b-1]의 문자가 같은 경우, lcs_arr[a-1][b-1]에 1을 더한 값을 lcs_arr[a][b]에 저장한다.
        2. A[a-1]와 B[b-1]의 문자가 다른 경우, lcs_arr[a-1][b]과 lcs_arr[a][b-1] 중 더 큰 값을 lcs_arr[a][b]에 저장한다.
4. StringBuilder 객체 sb를 생성하고, a에 A.length, b에 B.length를 저장한다.
5. lcs_arr[a][b]가 0보다 크다면 반복한다.
        1. lcs_arr[a][b]와 lcs_arr[a][b-1]가 같은 경우, lcs_arr[a][b-1]로 이동하기 위해 b를 1 줄인다.
        2. lcs_arr[a][b]와 lcs_arr[a-1][b]가 같은 경우, lcs_arr[a-1][b]로 이동하기 위해 a를 1 줄인다.
        3. 위 두 경우가 아니라면, A[a-1]과 B[b-1]은 같은 문자라는 의미로 sb에 A[a-1]을 저장하고, a와 b를 1씩 줄인다.
6. sb를 뒤집어서 LCS를 만든다.
7. LCS 길이인 lcs_arr[A.length][B.length]와 LCS 중 하나인 sb를 출력한다.

💻 전체 코드

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class LCS2_9252 {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        char[] A = br.readLine().trim().toCharArray();
        char[] B = br.readLine().trim().toCharArray();
        int[][] lcs_arr = new int[A.length + 1][B.length + 1];

        for (int a = 1; a <= A.length; a++) {
            for (int b = 1; b <= B.length; b++) {
                if (A[a - 1] == B[b - 1]) {
                    lcs_arr[a][b] = lcs_arr[a - 1][b - 1] + 1;
                } else if (lcs_arr[a][b - 1] < lcs_arr[a - 1][b]) {
                    lcs_arr[a][b] = lcs_arr[a - 1][b];
                } else {
                    lcs_arr[a][b] = lcs_arr[a][b - 1];
                }
            }
        }

        StringBuilder sb = new StringBuilder();
        int a = A.length;
        int b = B.length;
        while (0 < lcs_arr[a][b]) {
            if (lcs_arr[a][b] == lcs_arr[a][b - 1]) {
                b--;
            } else if (lcs_arr[a][b] == lcs_arr[a - 1][b]) {
                a--;
            } else {
                sb.append(A[--a]);
                b--;
            }
        }
        System.out.println(lcs_arr[A.length][B.length]);
        System.out.print(sb.reverse());
    }
}

💫 리뷰

lcs 까먹지말자~~

 

https://www.acmicpc.net/problem/9251

소요 시간: 17분
메모리: 15748KB
시간: 104ms

🔥 문제

LCS(Longest Common Subsequence, 최장 공통 부분 수열)문제는 두 수열이 주어졌을 때, 모두의 부분 수열이 되는 수열 중 가장 긴 것을 찾는 문제이다. 예를 들어, ACAYKP와 CAPCAK의 LCS는 ACAK가 된다.

 

입력

첫째 줄과 둘째 줄에 두 문자열이 주어진다. 문자열은 알파벳 대문자로만 이루어져 있으며, 최대 1000글자로 이루어져 있다.

 

출력

첫째 줄에 입력으로 주어진 두 문자열의 LCS의 길이를 출력한다.

 

 


🍀 풀이

LCS는 최장 공통 부분 수열(Longest Common Subsequence)을 의미한다.

Longest Common Substring과 비슷해보이지만 둘은 다르다!

 

ACAYKP와 CAPCAK의 Longest Common Substring은 CA지만 (ACAYKP, CAPCAK)

Longest Common Subsequence는 ACAK이다. (ACAYKP, CAPCAK)

 

이번 문제는 LCS를 찾는 문제이다. LCS는 DP문제이며, 푸는 방식이 있다.

먼저 문자열 A(ACAYKP), B(CAPCAK)의 길이+1에 맞는 2차원 배열 lcs를 만들고, 0번째 값은 모두 0으로 채운다.

 

이제 문자열 A와 B를 하나씩 비교한다.

A[a]와 B[b]의 문자가 같은 경우, lcs[a][b]+1 한 값을 lcs[a+1][b+1]에 저장한다.

 

lcs[a][b]는 A의 이전까지의 lcs 길이가 저장되어있을 것이므로, lcs[a][b]에 1을 더해 lcs[a+1][b+1]에 저장하는 것은 현재 문자 A[a](B[b])를 포함한 lcs 길이를 의미한다.

 

 

A[a]와 B[b]의 문자가 다른 경우, lcs[a][b+1]과 lcs[b+1][a] 중 더 큰 값을 가져와 저장한다.

문자가 다르기 때문에 lcs에 포함될 수 없으므로, A[a]와 B[b-1]까지 비교했을때 lcs 길이와 A[a-1]와 B[b]까지 비교했을때 lcs 길이를 비교해서 저장한다.

 

모든 문자들을 비교하고 나면 배열의 끝에는 lcs의 길이 값이 저장되어 있을 것이다.

1. 문자열 A와 B를 입력받고, 문자 배열로 저장한다.
2. int형 2차원 배열 lcs_arr를 정의한다.
3. 문자열 B와 문자열 A를 2중 for문을 사용하여 모든 문자끼리 비교할 수 있도록 한다.
        1. A[a-1]와 B[b-1]의 문자가 같은 경우, lcs_arr[b-1][a-1]에 1을 더한 값을 lcs_arr[b][a]에 저장한다.
        2. A[a-1]와 B[b-1]의 문자가 다른 경우, lcs_arr[b-1][a]과 lcs_arr[b][a-1] 중 더 큰 값을 lcs_arr[b][a]에 저장한다.
4. 모든 문자를 비교하였다면 맨 끝값인 lcs_arr[B.length][A.length]를 출력한다.

💻 전체 코드

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        char[] A = br.readLine().toCharArray();
        char[] B = br.readLine().toCharArray();
        int[][] lcs_arr = new int[B.length + 1][A.length + 1];

        for (int b = 1; b <= B.length; b++) {
            for (int a = 1; a <= A.length; a++) {
                if (A[a - 1] == B[b - 1]) {
                    lcs_arr[b][a] = lcs_arr[b - 1][a - 1] + 1;
                } else {
                    lcs_arr[b][a] = Math.max(lcs_arr[b - 1][a], lcs_arr[b][a - 1]);
                }
            }
        }
        System.out.println(lcs_arr[B.length][A.length]);
    }
}

💫 리뷰

lcs처럼 풀이법이 있는 알고리즘들을 찾아서 익혀야겠다!!🔥

https://www.acmicpc.net/problem/1261

소요 시간: 20분
메모리: 19544KB
시간: 256ms

🔥 문제

알고스팟 운영진이 미로에 갇혔다. 미로는 N*M 크기이며, 총 1*1크기의 방으로 이루어져 있다. 미로는 빈 방 또는 벽으로 이루어져 있고, 빈 방은 자유롭게 다닐 수 있지만, 벽은 부수지 않으면 이동할 수 없다. 어떤 방에서 이동할 수 있는 방은 상하좌우로 인접한 빈 방이다. 알고스팟의 무기 AOJ를 이용해 벽을 부수어 버릴 수 있다. 벽을 부수면, 빈 방과 동일한 방으로 변한다.

현재 (1, 1)에 있는 알고스팟 운영진이 (N, M)으로 이동하려면 벽을 최소 몇 개 부수어야 하는지 구하는 프로그램을 작성하시오.

 

입력

첫째 줄에 미로의 크기를 나타내는 가로 크기 M, 세로 크기 N (1 ≤ N, M ≤ 100)이 주어진다.

다음 N개의 줄에는 미로의 상태를 나타내는 숫자 0과 1이 주어진다. 0은 빈 방을 의미하고, 1은 벽을 의미한다.

(1, 1)과 (N, M)은 항상 뚫려있다.

 

출력

첫째 줄에 알고스팟 운영진이 (N, M)으로 이동하기 위해 벽을 최소 몇 개 부수어야 하는지 출력한다.

 


🍀 풀이

벽을 최소로 부수면서 탈출구에 도착하는 문제로, 제일 먼저 떠오른 알고리즘인 bfs(너비 우선 탐색)로 문제를 풀었다.

 

오래 이동을 하더라도 벽을 최소로 부수면서 탈출해야한다. 벽을 최소로 부순다는 조건을 만족시키기 위해 우선순위 큐를 이용하였다.

우선순위 큐에는 new int[] {행값, 열값, 벽을 부순 횟수}를 넣을 것이다.

그러므로 아래와 같이 벽을 부순 횟수를 오름차순으로 정렬하도록 설정하였다.

PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[2]));

 

그리고 bfs를 통해서 우선순위 큐의 원소를 빼서 `node`에 저장한다.

`node`를 상하좌우로 이동시켰을 때 보드판을 벗어나지 않았고, 한번도 방문한 적 없는 위치인 경우, 

  1. 이동한 위치가 탈출구라면, 벽을 부순 횟수 `node[2]`를 출력한다.
  2. 이동한 위치가 빈 공간이라면, 방문처리 후 이동한 위치와 벽을 부순 횟수`node[2]`를 우선순위 큐에 넣는다.
  3. 이동한 위치가 벽이라면, 방문처리 후 이동한 위치와 벽을 부순 횟수`node[2]+1`를 우선순위 큐에 넣는다.
1. 보드판을 입력받아, `map`에 저장한다.
2. `bfs()`함수를 호출한다. 이 함수는 운영진이 탈출했을 때 벽을 부순 최소 횟수를 반환한다.
3. 우선순위 큐 `pq`를 정의한다. `pq`는 벽을 부순 횟수를 오름차순으로 정렬한다. new int[] {행값, 열값, 벽을 부순 횟수}
4. 방문 처리를 위해서 boolean 2차원 배열 `visited`를 정의한다.
5. 운영진들의 첫 위치인 (0,0)와 벽을 부순 횟수(0)을 `pq`에 넣고, 방문처리한다.  
6. `pq`가 빌 때까지 반복한다.
        1. `pq`에서 원소를 빼 `node`에 저장한다.
        2. 상하좌우 사방탐색을 한다. 이동한 위치가 유효범위 내에 있고, 방문한 적이 없는 곳일 때,
                1. 이동한 위치가 탈출구라면, 벽을 부순 최소 횟수 `node[2]`를 반환하고 함수를 종료한다.
                2. 이동한 위치가 빈 공간이라면, 운영진들이 이동한 위치와 벽을 부순 횟수(`node[2]`)을 `pq`에 넣고, 방문처리한다.
                3. 이동한 위치가 벽이라면, 운영진들이 이동한 위치와 벽을 부순 횟수(`node[2]+1`)을 `pq`에 넣고, 방문처리한다.
7.`bfs()`함수가 종료되면, 반환된 값을 출력한다.

💻 전체 코드

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Comparator;
import java.util.PriorityQueue;

public class Main {
    static int[] di = new int[]{-1, 0, 1, 0};
    static int[] dj = new int[]{0, 1, 0, -1};
    static int N, M;
    static char[][] map;


    public static void main(String[] args) throws Exception {
        init();
        System.out.println(bfs());
    }

    static void init() throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String input = br.readLine();
        N = Integer.parseInt(input.substring(0, input.indexOf(' ')));
        M = Integer.parseInt(input.substring(input.indexOf(' ') + 1));
        map = new char[M][N];
        for (int m = 0; m < M; m++) {
            map[m] = br.readLine().toCharArray();
        }
    }

    static int bfs() {
        PriorityQueue<int[]> pq = new PriorityQueue<>(Comparator.comparingInt(a -> a[2]));
        boolean[][] visited = new boolean[M][N];

        pq.offer(new int[]{0, 0, 0});
        visited[0][0] = true;

        while (!pq.isEmpty()) {
            int[] node = pq.poll();

            for (int z = 0; z < 4; z++) {
                int ni = node[0] + di[z];
                int nj = node[1] + dj[z];

                if (check(ni, nj) && !visited[ni][nj]) {
                    if (ni == M - 1 && nj == N - 1) return node[2];
                    pq.offer(new int[]{ni, nj, map[ni][nj] == '1' ? node[2] + 1 : node[2]});
                    visited[ni][nj] = true;
                }
            }
        }

        return 0;
    }

    static boolean check(int i, int j) {
        return 0 <= i && i < M && 0 <= j && j < N;
    }

}

💫 리뷰

N과 M이 반대로 되어 있다! 문제를 꼼꼼하게 읽자!!

'0-1 bfs'로 풀 수 있다고 하는데, 처음보는 개념이라 먼저 공부하고 포스팅해야겠다!

https://www.acmicpc.net/problem/3078

소요 시간: 16분
메모리: 39280KB
시간: 236ms

🔥 문제

상근이네 반의 N명 학생들의 이름이 성적순으로 주어졌을 때, 좋은 친구가 몇 쌍이나 있는지 구하는 프로그램을 작성하시오.

좋은 친구는 등수의 차이가 K보다 작거나 같으면서 이름의 길이가 같은 친구이다.

 

입력

첫째 줄에 N과 K가 주어진다. (3 ≤ N ≤ 300,000, 1 ≤ K ≤ N)

다음 N개 줄에는 상근이네 반 학생의 이름이 성적순으로 주어진다. 이름은 알파벳 대문자로 이루어져 있고, 2글자 ~ 20글자이다.

 

출력

첫째 줄에 좋은 친구가 몇 쌍이 있는지 출력한다.


🍀 풀이

등수 순서대로 K명의 학생들의 이름을 카운트해서 배열에 저장하는 방식으로, 슬라이딩 윈도우를 활용해서 문제를 풀었다.

 

6 3
CYNTHIA
LLOYD
STEVIE
KEVIN
MALCOLM
DABNEY

 

위와 같은 입력이 주어졌다면, 등수 순서대로 아래와 같은 학생 이름 길이의 배열을 만들 수 있다.

 

1등 학생과 등수 차이가 K이하인 학생들의 이름 길이를 `name_len_count`배열에 카운트한다.

그리고 `name_len_count[7]`이 1등 학생을 포함하여 1등 학생과 이름 길이가 같은 학생의 수가 된다.

1등 학생과 좋은 친구 관계인 학생 수는 `name_len_count[7]-1`인 0명이 된다.

 

2등 학생과 좋은 관계인 학생 수를 찾기 위해 1등 학생의 이름 길이를 `name_len_count`배열에서 1 뺀다.

2등 학생과 등수 차이가 K이하인, 2등 이후 등수인 학생들의 이름 길이를 `name_len_count`배열에 카운트해야 한다.

2등 이전 등수는 이미 해당 등수에서 2등과 관계를 체크했으므로 2등 이후 등수인 학생들만 확인을 하면 된다.

이미 2등부터 4등(2+K-1등)까지 학생 이름 길이는 카운트가 되어 있으니, 범위의 끝 등수 학생인 5등 학생의 이름 길이만 `name_len_count`배열에 카운트하면 된다.

2등 학생과 좋은 친구 관계인 학생 수는 `name_len_count[5]-1`인 1명이 된다.

3등 학생과 좋은 관계인 학생 수를 찾기 위해 2등 학생의 이름 길이를 `name_len_count`배열에서 1 빼고, 범위의 끝 등수 학생인 6등 학생의 이름 길이를 카운트한다.

3등 학생과 좋은 친구 관계인 학생 수는 `name_len_count[6]-1`인 1명이 된다.

4등 학생과 좋은 관계인 학생 수를 찾기 위해 3등 학생의 이름 길이를 `name_len_count`배열에서 1 뺀다.

전체 학생 수는 6명으로 범위의 끝 등수 학생인 7등 학생이 없으므로 카운트하지 않는다.

3등 학생과 좋은 친구 관계인 학생 수는 `name_len_count[5]-1`인 0명이 된다.

이러한 방식으로 6등 학생까지 좋은 친구 관계를 확인하면 좋은 친구는 총 2쌍이 나온다.

 

1. 등수 순으로 학생의 이름 길이를 입력받는다. 이때 1등부터 K+1등 학생의 이름 길이를 `name_len_count` 배열에 카운트한다.
2. 좋은 친구가 몇쌍인지 저장하는 `pair`에 1등 학생과 좋은 친구 관계인 학생 수를 저장한다.
3. 이후 2등 학생부터 순차적으로 접근하며 좋은 친구 관계인 학생 수를 저장한다.
        1. i + K등 학생이 있는 경우 해당 학생의 이름 길이를 `name_len_count` 배열에 카운트한다.
        2. `pair`에 i등 학생과 이후 등수 중 좋은 친구 관계인 학생 수를 저장한다.
4. `pair`를 출력한다.

💻 전체 코드

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class Main {

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String input = br.readLine();
        int N = Integer.parseInt(input.substring(0, input.indexOf(' ')));
        int K = Integer.parseInt(input.substring(input.indexOf(' ') + 1));

        int[] name_len = new int[N];
        int[] name_len_count = new int[21];

        for (int i = 0; i < N; i++) {
            name_len[i] = br.readLine().length();
            if (i <= K) {
                name_len_count[name_len[i]]++;
            }
        }
        long pair = --name_len_count[name_len[0]];

        for (int i = 1; i < N; i++) {
            if (i + K < N) name_len_count[name_len[i + K]]++;
            pair += --name_len_count[name_len[i]];
        }

        System.out.print(pair);
    }
}

💫 리뷰

풀이가 바로 생각나서 빠르게 풀 수 있었다.😀

좋은 학생 관계 수는 int형 범위를 벗어날 수 있어서 long형으로 선언해야 한다.

코테에서도 이런거 잘 계산해서 풀자!

1. Java8 설치

java -version 명령어를 입력하면 아직 자바를 설치하지 않았으므로 자바가 없다고 뜨고 아래처럼 버전별로 자바 설치 명령어를 알려준다.

 

나는 Java8을 설치하였다. 설치한 후 다시 java -version을 입력하면 아래처럼 설치한 자바 버전이 보일 것이다.


2. 타임존 변경

 

EC2 서버의 기본 타임존은 UTC로 한국의 시간대가 아니다. 타임존을 변경하지 않으면 서버에서 실행되는 자바 애플리케이션에서 생성되는 시간이 모두 UTC 기준이라 한국과 9시간이 차이가 나기 때문에 꼭 수정해야 한다.

 

아래의 명령어를 순차적으로 수행하여 타임존을 변경한다.

sudo rm /etc/localtime
sudo ln -s /usr/share/zoneinfo/Asia/Seoul /etc/localtime

 

date 명령어를 통해서 타임존이 잘 변경되었는지 확인할 수 있다.


3. 호스트네임 변경

각 서버가 어느 서비스인지 표현하기 위해서 호스트네임을 변경할 것이다.

아래의 명령어를 통해서 호스트네임을 변경했다.

sudo hostnamectl set-hostname 변경할_호스트명

 

재부팅하면 호스트네임이 잘 변경되었는지 확인할 수 있다.

 

호스트네임을 변경했다면, 호스트 주소를 찾을 때 가장 먼저 검색해보는 /etc/hosts에 변경한 호스트네임을 등록해야 한다.

sudo vim /etc/hosts

 

파일을 열고 변경한 호스트네임을 등록한다.

i 를 누른 후 입력하고, esc를 누르고 :wq을 눌러 저장한다.

 

잘 등록되었는지 확인하기 위해서 curl 명령어를 사용한다.

curl 호스트네임

 

/etc/hosts에 변경한 호스트네임이 잘 등록되었다면, 두 번째 줄처럼 결과가 나올 것이다.

만약 등록에 실패했다면, 네 번째 줄처럼 결과가 나올 것이다.

 

📚 참고
[1] 스프링 부트와 AWS로 혼자 구현하는 웹 서비스, 2019

Mac에서 EC2 서버에 접속하기 위해서 터미널을 활용할 것이다.

외부 서버로 SSH에 접속하기 위해서는 아래와 같은 명령어를 매번 입력해야 한다.

ssh -i pem키_위치 EC2의_탄력적_IP주소

 

접속하기 위해 매번 키 위치랑 IP주소를 넣는다는건 너무 귀찮은 일이다.. 😞

이를 쉽게 할 수 있도록 설정해보자!

아래 명령어를 입력하여 pem 키를 ~/.ssh 디렉토리로 복사한다.

cp pem키_위치 ~/.ssh/

키가 잘 복사되었는지 확인

 

pem키가 복사되었다면, 키의 권한을 변경한다. 소유자만 읽고 쓸 수 있고, 나머지는 권한이 없는 600으로 설정한다.

chmod 600 ~./ssh/pem키_이름

 

 

다음으로 pem키가 있는 ~/.ssh 디렉토리에 config 파일을 만든다.

vim ~/.ssh/config

 

i 버튼을 눌러 Host를 작성한 후 esc를 누르고, :wq 을 입력하고 엔터를 쳐서 저장한다.

Host 본인이 원하는 서비스명
	HostName EC2 탄력적 IP주소
    User ubuntu
    IdentityFile ~/.ssh/pem키_이름

 

생성된 config 파일은 실행 권한이 필요하므로 700으로 권한 설정을 한다.

chmod 700 ~./ssh/config

 

실행 권한까지 모두 설정했다면 아래의 명령어로 EC2 서버에 접속한다.

ssh config에_등록한_서비스명

 

📚 참고
[1] 스프링 부트와 AWS로 혼자 구현하는 웹 서비스, 2019

1. 스토리지 크기 변경

EC2 서비스 대시보드 왼쪽 메뉴에서 [Elastic Block Store-볼륨]을 클릭하자!

찾지 못했다면 검색으로 '볼륨'을 검색해 EC2 기능이라고 적힌 볼륨을 클릭하면 된다.

 

크기 기본값은 8GB이다. 프리티어는 30GB까지 가능하므로 최대치로 늘려주자!

볼륨 ID를 클릭하면 오른쪽에 [수정] 버튼이 보일 것이다.

크기를 수정하고 [수정] 버튼을 누르면 아래와 같이 크기가 변경된 것을 확인할 수 있다.


2. 보안 그룹 추가

보안 그룹은 방화벽을 의미한다. EC2 서비스 대시보드 왼쪽 메뉴에서 [네트워크 및 보안-보안 그룹]을 클릭한다.

default가 아닌 하나가 있을 텐데, 그것의 보안 그룹 ID를 클릭한다.

 

[인바운드 규칙 편집] 버튼을 누르고 아래와 같이 설정한다.

 

SSH면서, 포트 22인 경우는 AWS EC2에 터미널로 접속할 때이다.

전체 오픈(0.0.0.0/0)을 하면 pem 키가 깃허브에 실수로 노출되는 순간..😱

그래서 지정된 IP에서만 SSH 접속이 가능하도록 하기 위해서, 소스를 '내 IP'로 설정하였다.

다른 장소로 이동할 경우에는 그 곳의 IP를 SSH 규칙에 등록시키면서 안전하게 사용하자! 


3. 탄력적 IP 할당

탄력적 IP(Elastic IP, EIP)는 AWS의 고정 IP를 말한다.

인스턴스도 하나의 서버이기 때문에 IP가 있다. 인스턴스가 생성되면 IP를 새롭게 할당하는데, 인스턴스를 중지하고 다시 시작할 때도 새 IP가 할당된다. 이렇게 중지하고 다시 시작하는 걸 반복하는 경우 IP주소를 계속 확인해야 하는 번거로움이 생긴다. 그래서 고정 IP를 할당받아 이런 번거로운 일이 생기지 않도록 할 수 있다.

 

EC2 서비스 대시보드 왼쪽 메뉴에서 [네트워크 및 보안-탄력적 IP]를 클릭한다.

오른쪽에 [탄력적 IP 주소 할당]을 클릭하고, [할당] 버튼을 눌러서 탄력적 IP를 할당받는다. 할당을 받은 탄력적 IP를 선택하고, 작업을 눌러 탄력적 IP 주소와 EC2 서버와 연결한다.

 

 

연결할 인스턴스와 프라이빗 주소를 선택하고 연결을 누른다.

 

인스턴스 정보를 확인하면 탄력적 IP 주소가 연결된 것을 확인할 수 있다.

 

🚨 탄력적 IP를 생성하고 EC2 서버에 연결하지 않으면 비용이 발생할 수 있으니, 탄력적 IP를 생성하자마자 바로 연결하자!

더 이상 사용할 인스턴스가 없으면 탄력적 IP도 바로 삭제해야 한다.

 

📚 참고
[1] 스프링 부트와 AWS로 혼자 구현하는 웹 서비스, 2019

'AWS' 카테고리의 다른 글

[AWS] EC2에 접속 후 설정  (0) 2024.05.04
[AWS] EC2 서버에 접속하기 (Mac)  (0) 2024.05.04
[AWS] EC2 인스턴스 생성하기  (0) 2024.05.04
[AWS] 과금 없이 안전하게 AWS 쓰기  (0) 2024.05.03

오늘은 EC2 인스턴스를 생성하려고 한다!

EC2는 AWS에서 제공하는 성능, 용량 등을 유동적으로 사용할 수 있는 서버이다.
인스턴스란, EC2 서비스에 생성된 가상머신이다.

 

먼저, AWS 사이트에 로그인을 한 후 오른쪽 상단에 있는 리전을 서울로 변경한다.

 

다음으로 'ec2'를 검색한다. (옆에 별표 모양을 클릭하면 즐겨찾기로 상단에 EC2로 가는 버튼이 생겨난다.)

 

EC2를 클릭하면 EC2 대시보드가 나올 것이다.

좌측 메뉴에서 [인스턴스]를 클릭하고, 중앙이나 오른쪽에 있는 [인스턴스 시작] 버튼을 눌러서 인스턴스를 생성하자!

 

인스턴스의 이름을 작성하고, 애플리케이션은 우분투(ubuntu)를 선택한다. 

 

AMI는 프리티어는 선택할 수 있는 게 한정적이기 때문에, 그 안에서 선택했다.

AMI(Amazon Machine Image)는 EC2 인스턴스를 시작하는 데 필요한 정보를 이미지로 만들어 둔 것이다.

 

인스턴스로 접근하기 위해서는 키(비밀키)가 필요하다. 인스턴스는 지정된 키와 매칭되는 공개키를 가지고 있어서 해당 키 외에는 접근을 허용하지 않는다. 이 키는 절대로 유출되면 안되고, 키 페어 파일은 재발급이 불가능하다. 서버 접속에 필요하니 잘 관리해야 한다!!

[새 키 페어 생성] 버튼을 눌러서 키 페어를 생성한다.

 

키 페어 이름을 작성하고, 기본 선택인 RSA와 .pem을 유지한 상태로 키 페어를 생성한다.

 

오른쪽 하단에 있는 [인스턴스 시작] 버튼을 누르면 인스턴스가 생성된다.

 

 

 

📚 참고
[1] 스프링 부트와 AWS로 혼자 구현하는 웹 서비스, 2019

+ Recent posts