<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>호소세의 개발 블로그</title>
    <link>https://pabeba.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 25 Aug 2026 18:10:28 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>호소세</managingEditor>
    <image>
      <title>호소세의 개발 블로그</title>
      <url>https://tistory1.daumcdn.net/tistory/5601481/attach/7934065fdb664710b67a11102af35c1e</url>
      <link>https://pabeba.tistory.com</link>
    </image>
    <item>
      <title>AWS - Terraform - 코드형 인프라(IaC) : 테라폼 프로젝트 기본 구성 및 초기화(init) 가이드</title>
      <link>https://pabeba.tistory.com/297</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이전 시간 내용 참고 후 진행하면 더 좋습니다. aws 계정 등록해야합니다!&lt;/p&gt;
&lt;div&gt;
&lt;div id=&quot;model-response-message-contentr_83d925014b177dbf&quot;&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://pabeba.tistory.com/296&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://pabeba.tistory.com/296&lt;/a&gt;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size26&quot;&gt;1. 개요: 테라폼 프로젝트를 구성하는 핵심 파일들&lt;/h2&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;테라폼은 특정 디렉토리에 있는 .tf 확장자를 가진 파일들을 읽어 들여 인프라를 구성합니다.&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;비록 하나의 파일에 모든 코드를 담을 수도 있지만,&lt;/span&gt;&lt;span&gt; 실무에서는 &lt;/span&gt;&lt;b data-index-in-node=&quot;86&quot; data-path-to-node=&quot;8&quot;&gt;관리의 용이성, 재사용성, 가독성&lt;/b&gt;&lt;span&gt;을 위해 목적에 따라 파일을 분리하여 구성하는 것이 표준 관례(Best Practice)입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이번 실습에서 생성하고 작성할 핵심 파일들의 역할은 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;  테라폼 기본 구성 파일 설명&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div data-ved=&quot;0CAAQ3ecQahgKEwjawO2yzvGVAxUAAAAAHQAAAAAQ8gQ&quot; data-hveid=&quot;0&quot;&gt;파일명의미 및 역할 (Description)
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;11&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;11,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,1,0,0&quot;&gt;provider.tf&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;11,1,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,1,1,0&quot;&gt;'누구에게' 명령을 내릴지 정의하는 파일&lt;/b&gt;입니다. AWS, Azure, GCP 등 인프라를 제공하는 공급자(Provider) 설정과 사용할 버전을 명시합니다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;11,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,2,0,0&quot;&gt;main.tf&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;11,2,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,2,1,0&quot;&gt;'무엇을' 만들지 정의하는 메인 파일&lt;/b&gt;입니다. 실제 리소스(EC2, VPC 등)를 생성하는 핵심 코드가 주로 이곳에 작성됩니다. 프로젝트 규모가 커지면 다른 이름의 .tf 파일로 분리하기도 합니다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;11,3,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,3,0,0&quot;&gt;variables.tf&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;11,3,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,3,1,0&quot;&gt;코드 내에서 사용할 변수(Variable)들의 '입력 타입'을 정의하는 파일&lt;/b&gt;입니다. 코드의 재사용성을 높이기 위해 하드코딩 대신 변수를 선언합니다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;11,4,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,4,0,0&quot;&gt;terraform.tfvars&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;11,4,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,4,1,0&quot;&gt;variables.tf에서 정의한 변수에 실제 '값'을 할당하는 파일&lt;/b&gt;입니다. 민감한 정보(비밀번호, 키 등)가 포함될 수 있어 주의가 필요합니다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;11,5,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,5,0,0&quot;&gt;outputs.tf&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;11,5,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,5,1,0&quot;&gt;인프라 생성 후 인프라의 '결과 값'을 출력하는 파일&lt;/b&gt;입니다. 생성된 EC2의 퍼블릭 IP나 S3 버킷의 URL 등, 다른 프로젝트나 사용자가 확인해야 할 정보를 정의합니다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;11,6,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,6,0,0&quot;&gt;.gitignore&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;11,6,1,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,6,1,0&quot;&gt;Git 버전 관리에서 제외할 파일 목록을 지정&lt;/b&gt;합니다. 테라폼 초기화 시 생성되는 임시 폴더나 민감한 정보가 담긴 .tfvars 파일 등을 Git에 업로드하지 않도록 방지합니다.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size26&quot;&gt;2. 실습 1단계: 테라폼 프로젝트 기본 파일 구성&lt;/h2&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;가장 먼저 실습 공간을 만들고,&lt;/span&gt;&lt;span&gt; 위에서 설명한 기본 파일들을 생성해 보겠습니다.&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;PowerShell을 열고 아래 명령어를 한 줄씩 실행하거나 전체 복사하여 실행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;디렉토리는 다들 자신의 디렉토리로 변경하셔야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjawO2yzvGVAxUAAAAAHQAAAAAQ9AQ&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;php&quot;&gt;&lt;code&gt;# 1. 실습 디렉토리 생성 및 이동 (경로는 본인 환경에 맞게 수정 가능)
$path = &quot;C:\Users\NT551_11TH\OneDrive\Desktop\workspace\tf_project\basic&quot;
New-Item -ItemType Directory -Path $path -Force
cd $path

# 2. 테라폼 핵심 구성 파일(공파일) 한 번에 생성하기
'provider.tf', 'main.tf', 'variables.tf', 'outputs.tf', 'terraform.tfvars', '.gitignore' | ForEach-Object { New-Item -ItemType File -Path $_ -Force }
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;16&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;명령어 실행이 완료되면 해당 폴더에 6개의 공파일이 생성된 것을 확인할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size26&quot;&gt;3. 실습 2단계: Provider 설정 (provider.tf 작성)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 테라폼에게 우리는 AWS 클라우드의 서울 리전(ap-northeast-2)에 인프라를 구축할 것이라고 알려주는 설정을 &lt;/span&gt;provider.tf&lt;span&gt; 파일에 작성합니다.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjawO2yzvGVAxUAAAAAHQAAAAAQ9QQ&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;# provider.tf 파일 내용

terraform {
  # 테라폼 자체 설정 (필요한 프로바이더 버전 명시)
  required_providers {
    aws = {
      source  = &quot;hashicorp/aws&quot;
      version = &quot;~&amp;gt; 5.0&quot; # 5.0 버전 이상을 사용하되 최신 마이너 버전 허용
    }
  }
}

# AWS 프로바이더 설정
provider &quot;aws&quot; {
  region = &quot;ap-northeast-2&quot; # 서울 리전
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size26&quot;&gt;4. 실습 3단계: 테라폼 파이프라인 가동 (init &amp;amp; validate)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;파일 작성이 완료되었다고 바로 인프라를 생성할 수 없습니다.&lt;/span&gt;&lt;span&gt; 테라폼이 구동하기 위한 준비 과정이 필요합니다.&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;터미널에서 아래 명령어를 차례로 실행해 보세요.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;24&quot; data-ke-size=&quot;size23&quot;&gt;Step 1: 테라폼 초기화 (terraform init)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;25&quot; data-ke-size=&quot;size16&quot;&gt;init&lt;span&gt; 명령은 테라폼 프로젝트가 위치한 디렉토리에서 &lt;/span&gt;&lt;b data-index-in-node=&quot;30&quot; data-path-to-node=&quot;25&quot;&gt;가장 먼저, 그리고 딱 한 번 실행&lt;/b&gt;&lt;span&gt;해야 하는 명령어입니다.&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;25&quot; data-ke-size=&quot;size16&quot;&gt;provider.tf&lt;span&gt;를 읽고 필요한 AWS 플러그인(Provider 바이너리)을 다운로드하는 등의 준비 작업을 수행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjawO2yzvGVAxUAAAAAHQAAAAAQ9gQ&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;terraform init
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-path-to-node=&quot;27&quot; data-ke-size=&quot;size20&quot;&gt;  초기화 성공 후 생성되는 결과물 분석&amp;nbsp;&lt;/h4&gt;
&lt;p data-path-to-node=&quot;28&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;초기화에 성공하면 폴더 내에 새로운 임시 폴더와 파일이 숨겨진 상태로 생성됩니다.&lt;/span&gt;&lt;span&gt; 이들의 역할은 다음과 같습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;29&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,0,0&quot;&gt;.terraform/ (폴더)&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;29,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,0,1,0,0&quot;&gt;의미&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 테라폼이 인프라 공급자(AWS 등)와 통신하기 위해 다운로드한 &lt;/span&gt;&lt;b data-index-in-node=&quot;39&quot; data-path-to-node=&quot;29,0,1,0,0&quot;&gt;프로바이더 플러그인 바이너리 파일&lt;/b&gt;&lt;span&gt;들이 저장되는 로컬 임시 저장소입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;i data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,0,1,1,0&quot;&gt;주의: 이 폴더는 용량이 크고 환경마다 다르므로 .gitignore에 등록하여 Git에 절대 올리지 않습니다.&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,1,0&quot;&gt;.terraform.lock.hcl (파일)&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;29,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,1,1,0,0&quot;&gt;의미&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 프로젝트가 사용하는 프로바이더의 모듈명,&lt;/span&gt;&lt;span&gt; 정확한 버전,&lt;/span&gt;&lt;span&gt; 그리고 해시값(Checksum)을 기록하여 잠그는(Lock) 파일입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;i data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,1,1,1,0&quot;&gt;역할&lt;/i&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 나중에 다른 팀원이나 서버에서 이 프로젝트를 구동할 때,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;b data-index-in-node=&quot;36&quot; data-path-to-node=&quot;29,1,1,1,0&quot;&gt;항상 동일한 버전의 프로바이더가 사용되도록 보장&lt;/b&gt;&lt;span&gt;하여 예기치 않은 버전 업데이트로 인한 인프라 장애를 방지합니다.&lt;/span&gt;&lt;span&gt; 이 파일은 Git에 올려 함께 관리하는 것이 권장됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;31&quot; data-ke-size=&quot;size23&quot;&gt;Step 2: 코드 문법 검사 (terraform validate)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;32&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 작성한 HCL 코드가 테라폼 문법에 맞게 올바르게 작성되었는지 검증할 차례입니다.&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;32&quot; data-ke-size=&quot;size16&quot;&gt;init&lt;span&gt; 과정이 선행되어야 프로바이더별 고유한 속성 문법도 검증할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjawO2yzvGVAxUAAAAAHQAAAAAQ9wQ&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;terraform validate
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-path-to-node=&quot;34&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;34&quot;&gt;[실행 결과 확인]&lt;/b&gt;&lt;/h4&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjawO2yzvGVAxUAAAAAHQAAAAAQ-AQ&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;Success! The configuration is valid.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;36&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;36&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;위와 같이 &lt;/span&gt;&lt;b data-index-in-node=&quot;6&quot; data-path-to-node=&quot;36&quot;&gt;Success!&lt;/b&gt;&lt;span&gt; 메시지가 나타난다면,&lt;/span&gt;&lt;span&gt; 작성한 &lt;/span&gt;provider.tf&lt;span&gt; 코드의 문법에는 이상이 없다는 뜻입니다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;38&quot; data-ke-size=&quot;size26&quot;&gt; ️ 마치며&lt;/h2&gt;
&lt;p data-path-to-node=&quot;39&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;오늘은 코드형 인프라(IaC)의 핵심 도구인 테라폼을 사용하기 위한 가장 기초적인 단계인 프로젝트 파일 구성과,&lt;/span&gt;&lt;span&gt; 공급자(Provider) 설정 후 초기화(&lt;/span&gt;init&lt;span&gt;) 및 검증(&lt;/span&gt;validate&lt;span&gt;) 과정을 알아보았습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;40&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 로컬 PC의 테라폼 엔진이 AWS 서버와 통신할 준비가 모두 완료되었습니다.&lt;/span&gt;&lt;span&gt; 다음 포스팅에서는 실제로 &lt;/span&gt;&lt;b data-index-in-node=&quot;60&quot; data-path-to-node=&quot;40&quot;&gt;main.tf를 작성하여 AWS EC2 인스턴스를 코드 한 줄로 생성하고 삭제해 보겠습니다.&lt;/b&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;</description>
      <category>코딩 개발/AWS</category>
      <category>AWS</category>
      <category>init</category>
      <category>Terraform</category>
      <category>validate</category>
      <author>호소세</author>
      <guid isPermaLink="true">https://pabeba.tistory.com/297</guid>
      <comments>https://pabeba.tistory.com/297#entry297comment</comments>
      <pubDate>Mon, 24 Aug 2026 18:29:24 +0900</pubDate>
    </item>
    <item>
      <title>[IaC] 코드형 인프라(Infrastructure as Code) 개요 및 테라폼(Terraform) 개발 환경 구축 가이드</title>
      <link>https://pabeba.tistory.com/296</link>
      <description>&lt;p data-path-to-node=&quot;1&quot; data-ke-size=&quot;size16&quot;&gt;오늘은 클라우드 및 인프라 엔지니어링 생태계에서 가장 중요한 패러다임 중 하나인&lt;/p&gt;
&lt;p data-path-to-node=&quot;1&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드형 인프라&lt;/b&gt;(Infrastructure as Code, IaC)의 핵심 개념과,&lt;/p&gt;
&lt;p data-path-to-node=&quot;1&quot; data-ke-size=&quot;size16&quot;&gt;대표적인 IaC 도구인 &lt;b&gt;테라폼&lt;/b&gt;(Terraform)을 사용하기 위한 로컬 개발 환경 구축 방법을 한눈에 알기 쉽게 정리해 보겠습니다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;3&quot; data-ke-size=&quot;size26&quot;&gt;1. IaC(Infrastructure as Code) 개요&lt;/h2&gt;
&lt;h3 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size23&quot;&gt;IaC란 무엇인가요?&lt;/h3&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;IaC(Infrastructure as Code)는 사람이 AWS 콘솔이나 GCP 웹 화면에 접속하여 마우스 클릭으로 서버, 네트워크, 데이터베이스 등을 일일이 설정하는 대신, 명확하게 정의된 코드(텍스트 파일)를 통해 IT 인프라를 자동으로 생성, 수정, 삭제하는 기술입니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size23&quot;&gt;주요 특징&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;7&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,0,0&quot;&gt;인프라의 코드화(Text-based Definition)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;7,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;서버(EC2), 저장소(S3), 네트워크(VPC) 등의 인프라 구성 요소를 선언적 언어나 프로그래밍 언어 형태의 코드로 작성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,1,0&quot;&gt;동일성 및 멱등성(Idempotency) 보장&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;7,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드를 실행할 때마다 환경의 치우침 없이 &lt;b data-index-in-node=&quot;23&quot; data-path-to-node=&quot;7,1,1,0,0&quot;&gt;언제나 동일한 구성 결과&lt;/b&gt;를 보장받을 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;7,2,0&quot;&gt;버전 관리(Version Control) 용이&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;7,2,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인프라 설정 파일도 일반 소스 코드처럼 Git을 이용해 커밋, 브랜칭, 이력 추적 및 롤백(Rollback) 관리를 수행할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;IaC 도입 시 주요 장점&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;9&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,0,0&quot;&gt;휴먼 에러(Human Error) 방지&lt;/b&gt;: 웹 콘솔 클릭 실수로 인한 잘못된 설정이나 세팅 누락을 근본적으로 예방할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,1,0&quot;&gt;압도적으로 빠른 배포 속도&lt;/b&gt;: 수동 작업으로 수시간~수일이 걸리던 인프라 구축을 수초~수분 내에 마칠 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,2,0&quot;&gt;팀 내 협업 및 리뷰 용이&lt;/b&gt;: 코드 리뷰(Pull Request) 절차를 통해 인프라 변경 사항을 팀원들과 검증하고 간편하게 공유할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;11&quot; data-ke-size=&quot;size26&quot;&gt;2. 주요 IaC 제품군 비교&lt;/h2&gt;
&lt;p data-path-to-node=&quot;12&quot; data-ke-size=&quot;size16&quot;&gt;IaC 도구는 특정 클라우드 벤더 전용 도구와, 여러 클라우드를 아우르는 멀티 클라우드 도구로 구분됩니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size23&quot;&gt;1) AWS 전용 도구&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;14&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,0,0&quot;&gt;AWS CloudFormation&lt;/b&gt;: YAML 또는 JSON 형태의 선언적(Declarative) 템플릿 파일로 인프라를 정의하는 AWS의 기본 서비스입니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,1,0&quot;&gt;AWS CDK (Cloud Development Kit)&lt;/b&gt;: Python, TypeScript, Java, Go 등 익숙한 프로그래밍 언어를 그대로 사용하여 AWS 인프라를 생성할 수 있는 개발자 친화적 도구입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size23&quot;&gt;2) 멀티 클라우드 도구&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,0,0&quot;&gt;Terraform (테라폼)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사실상 글로벌 표준(De-facto Standard)으로 여겨지는 오픈소스/써드파티 프로비저닝 도구입니다.&lt;/li&gt;
&lt;li&gt;HashiCorp가 개발한 HCL(HashiCorp Configuration Language)이라는 직관적인 독자 언어를 사용합니다.&lt;/li&gt;
&lt;li&gt;AWS, GCP, Azure, 네이버클라우드 등 대부분의 클라우드 인프라를 하나의 도구로 통합 관리할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,0&quot;&gt;Ansible (앤서블)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;테라폼이 *'인프라 뼈대(프로비저닝)'*를 생성하는 데 집중한다면, 앤서블은 생성된 인프라 내부의 소프트웨어 설치나 설정 관리(&lt;i data-index-in-node=&quot;71&quot; data-path-to-node=&quot;16,1,1,0,0&quot;&gt;구성 관리, Configuration Management&lt;/i&gt;)에 특화된 도구입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;18&quot; data-ke-size=&quot;size26&quot;&gt;3. 테라폼 &amp;amp; AWS CLI 개발 환경 구축&lt;/h2&gt;
&lt;p data-path-to-node=&quot;19&quot; data-ke-size=&quot;size16&quot;&gt;이제 테라폼 코드를 작성하고 AWS 클라우드에 실제 인프라 명령을 전달할 수 있도록 로컬 PC 세팅을 진행해 보겠습니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size23&quot;&gt;Step 1. AWS CLI 설치 및 설정&lt;/h3&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;AWS CLI(Command Line Interface)는 터미널 쉘에서 AWS 서비스를 명령어로 관리할 수 있게 돕는 통합 오픈소스 도구입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;22&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22,0,0&quot;&gt;다운로드 패키지 설치&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;22,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22,0,1,0,0&quot;&gt;Windows&lt;/b&gt;: &lt;a href=&quot;https://awscli.amazonaws.com/AWSCLIV2.msi&quot; data-ved=&quot;0CAAQ_4QMahgKEwjCj4G38uqVAxUAAAAAHQAAAAAQnAI&quot; data-hveid=&quot;0&quot;&gt;AWS CLI V2 MSI 다운로드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22,0,1,1,0&quot;&gt;Mac&lt;/b&gt;: &lt;a href=&quot;https://awscli.amazonaws.com/AWSCLIV2.pkg&quot; data-ved=&quot;0CAAQ_4QMahgKEwjCj4G38uqVAxUAAAAAHQAAAAAQnQI&quot; data-hveid=&quot;0&quot;&gt;AWS CLI V2 PKG 다운로드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22,1,0&quot;&gt;설치 상태 확인 (터미널 새로 오픈 후 실행)&lt;/b&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjCj4G38uqVAxUAAAAAHQAAAAAQngI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;aws --version
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjCj4G38uqVAxUAAAAAHQAAAAAQnwI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;# 출력 예시
aws-cli/2.35.6 Python/3.14.5 Windows/11 exe/AMD64
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;25&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,0,0&quot;&gt;IAM 액세스키(Access Key) 설정&lt;/b&gt; 터미널에서 아래 명령어를 실행하고, 발급받은 IAM 액세스 키 정보를 입력합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjCj4G38uqVAxUAAAAAHQAAAAAQoAI&quot; data-hveid=&quot;0&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot; data-path-to-node=&quot;37&quot;&gt;Step 2. AWS IAM 인증 액세스키(Access Key) 발급 절차 및 주의사항&lt;/h3&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-path-to-node=&quot;38&quot; data-ke-size=&quot;size16&quot;&gt;테라폼이나 AWS CLI가 외부 로컬 PC에서 AWS 리소스에 접근하려면 인증 자격 증명이 필요합니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot; data-path-to-node=&quot;39&quot;&gt;
&lt;li&gt;&lt;b data-path-to-node=&quot;39,0,0&quot; data-index-in-node=&quot;0&quot;&gt;액세스 키 발급 과정&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-path-to-node=&quot;39,0,1&quot;&gt;
&lt;li&gt;AWS Console ➔ IAM 서비스 진입 ➔ 본인 계정/사용자 선택 ➔&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b data-path-to-node=&quot;39,0,1,0,0&quot; data-index-in-node=&quot;42&quot;&gt;보안 자격 증명(Security credentials)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;탭 선택&lt;/li&gt;
&lt;li&gt;[액세스 키] 항목에서&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b data-path-to-node=&quot;39,0,1,1,0&quot; data-index-in-node=&quot;13&quot;&gt;[액세스 키 만들기]&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;클릭&lt;/li&gt;
&lt;li&gt;사용 사례 선택 시&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b data-path-to-node=&quot;39,0,1,2,0&quot; data-index-in-node=&quot;11&quot;&gt;Command Line Interface(CLI)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;선택 후 안내 모범 사례 확인 체크 ➔ [다음] ➔ [액세스 키 만들기] 클릭&lt;/li&gt;
&lt;li&gt;CSV 파일 다운로드를 클릭하여 발급받은 Access Key ID와 Secret Access Key를 저장합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-path-to-node=&quot;39,1,0&quot; data-index-in-node=&quot;0&quot;&gt;액세스 키 관리 및 삭제 방법&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot; data-path-to-node=&quot;39,1,1&quot;&gt;
&lt;li&gt;필요가 없어진 키는 보안을 위해 IAM 콘솔에서 비활성화 처리 후 삭제하는 것이 모범 사례입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote style=&quot;color: #666666; text-align: start;&quot; data-path-to-node=&quot;40&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p style=&quot;color: #666666;&quot; data-path-to-node=&quot;40,0&quot; data-ke-size=&quot;size16&quot;&gt;⚠️&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b data-path-to-node=&quot;40,0&quot; data-index-in-node=&quot;3&quot;&gt;보안 주의사항 (중요!)&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;발급된 Secret Access Key는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b data-path-to-node=&quot;40,0&quot; data-index-in-node=&quot;40&quot;&gt;절대 외부로 유출되거나 GitHub 공개 저장소에 올려서는 안 됩니다.&lt;/b&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;해커들이 매크로 스크립트로 깃허브를 상시 모니터링하고 있으며, 유출 시 고성능 가상화 머신(채굴 등)이 무단 생성되어 방대한 비용 폭탄을 맞을 수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;img style=&quot;text-align: center; caret-color: transparent; letter-spacing: 0px;&quot; src=&quot;https://blog.kakaocdn.net/dna/bfFCyd/dJMcaf8rwks/AAAAAAAAAAAAAAAAAAAAACL-Tn733-8vsVxMVNfG9wf43ljBOVNCIQ3ETjI9TrAY/img.png?credential=yqXZFxpELC7KVnFOS48ylbz2pIh7yKj8&amp;amp;expires=1785509999&amp;amp;allow_ip=&amp;amp;allow_referer=&amp;amp;signature=BdodIEMlXVawzpsPa5w%2BXwbQK5Y%3D&quot; data-origin-width=&quot;1810&quot; data-origin-height=&quot;724&quot; data-is-animation=&quot;false&quot; /&gt;&lt;/div&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjCj4G38uqVAxUAAAAAHQAAAAAQoQI&quot; data-hveid=&quot;0&quot;&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 숨긴 후 아래 명령어 cmd나 powershell에서 작성합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그럼 id, access key, region name, output format을 작성하라고 나오는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 두 개는 iam 액세스 키 치시면 되고 지역은 자신이 쓰고있는 지역 작성 output format은 json으로 해주세요.&lt;/p&gt;
&lt;pre style=&quot;background-color: #f8f8f8; color: #383a42; text-align: start;&quot;&gt;&lt;code&gt;aws configure
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;AWS Access Key ID [None]: AKIA4BQ3...
AWS Secret Access Key [None]: NZkQwWX...
Default region name [ap-northeast-2]: ap-northeast-2
Default output format [json]: json
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;29&quot; data-ke-size=&quot;size23&quot;&gt;Step 3. Terraform 설치 및 시스템 경로(PATH) 등록&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;30&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;30,0,0&quot;&gt;다운로드&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;30,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;30,0,1,0,0&quot;&gt;Windows (AMD64)&lt;/b&gt;: &lt;a href=&quot;https://developer.hashicorp.com/terraform/install#windows&quot; data-ved=&quot;0CAAQ_4QMahgKEwjCj4G38uqVAxUAAAAAHQAAAAAQogI&quot; data-hveid=&quot;0&quot;&gt;HashiCorp Terraform Windows 다운로드&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;30,0,1,1,0&quot;&gt;Mac&lt;/b&gt;: &lt;a href=&quot;https://developer.hashicorp.com/terraform/install#darwin&quot; data-ved=&quot;0CAAQ_4QMahgKEwjCj4G38uqVAxUAAAAAHQAAAAAQowI&quot; data-hveid=&quot;0&quot;&gt;HashiCorp Terraform Mac 다운로드&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;30,1,0&quot;&gt;설치 및 환경변수 지정&lt;/b&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;30,1,1&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;압축 파일 내부의 terraform.exe 파일을 C:\terraform 경로에 저장합니다.&lt;/li&gt;
&lt;li&gt;Windows [시스템 속성] ➔ [환경 변수] ➔ Path 항목 편집에 C:\terraform 경로를 추가합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;394&quot; data-origin-height=&quot;340&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4xVYQ/dJMcaazpFPV/k4xxLhcFz7XHIhvTkZkUpK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4xVYQ/dJMcaazpFPV/k4xxLhcFz7XHIhvTkZkUpK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4xVYQ/dJMcaazpFPV/k4xxLhcFz7XHIhvTkZkUpK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4xVYQ%2FdJMcaazpFPV%2Fk4xxLhcFz7XHIhvTkZkUpK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;394&quot; height=&quot;340&quot; data-origin-width=&quot;394&quot; data-origin-height=&quot;340&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1813&quot; data-origin-height=&quot;903&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TuViu/dJMcafHvK8S/rVHlm0SAym6g31HmUSqkgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TuViu/dJMcafHvK8S/rVHlm0SAym6g31HmUSqkgk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TuViu/dJMcafHvK8S/rVHlm0SAym6g31HmUSqkgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTuViu%2FdJMcafHvK8S%2FrVHlm0SAym6g31HmUSqkgk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1813&quot; height=&quot;903&quot; data-origin-width=&quot;1813&quot; data-origin-height=&quot;903&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;30&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;30,2,0&quot;&gt;버전 확인&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjCj4G38uqVAxUAAAAAHQAAAAAQpAI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;ada&quot;&gt;&lt;code&gt;terraform --version
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjCj4G38uqVAxUAAAAAHQAAAAAQpQI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;# 출력 예시
Terraform v1.15.6 on windows_amd64
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;34&quot; data-ke-size=&quot;size23&quot;&gt;Step 4. VS Code 확장 프로그램 설치&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;35&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;VS Code 실행 ➔ Extensions(Ctrl + Shift + X) ➔ &lt;b data-index-in-node=&quot;44&quot; data-path-to-node=&quot;35,0,0&quot;&gt;HashiCorp Terraform&lt;/b&gt; 검색 후 [Install] 버튼 클릭&lt;/li&gt;
&lt;li&gt;&lt;i data-index-in-node=&quot;0&quot; data-path-to-node=&quot;35,1,0&quot;&gt;설치 효과&lt;/i&gt;: HCL 코드 구문 강조(Syntax Highlighting), 자동 완성을 지원받아 개발 생산성이 크게 향상됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;42&quot; data-ke-size=&quot;size26&quot;&gt;4. 테라폼 동작 매커니즘 한눈에 이해하기&lt;/h2&gt;
&lt;p data-path-to-node=&quot;43&quot; data-ke-size=&quot;size16&quot;&gt;테라폼으로 인프라가 구성되는 내부 흐름은 다음과 같은 단계로 연동되어 수행됩니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjCj4G38uqVAxUAAAAAHQAAAAAQpgI&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;[VS Code]에서 테라폼 코드(*.tf) 작성 및 적용 명령 실행
      &amp;darr;
[Terraform Engine]에서 HCL 언어 해석 및 생성할 인프라 계획 수립
      &amp;darr;
[AWS CLI / Provider]를 통해 AWS API 호출 명령어 집합 변환
      &amp;darr;
[IAM Access Key] 자격 증명을 거쳐 AWS 클라우드로 전송
      &amp;darr;
[AWS Cloud] 실제 EC2, VPC, S3 등 인프라 자동 생성/구성
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;45&quot; data-ke-size=&quot;size16&quot;&gt;이와 같은 흐름을 이해하고 계시면 추후 테라폼 코드를 작성하고 트러블슈팅할 때 커뮤니케이션과 문제 원인 파악이 한층 수월해집니다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;47&quot; data-ke-size=&quot;size26&quot;&gt;마치며&lt;/h2&gt;
&lt;p data-path-to-node=&quot;48&quot; data-ke-size=&quot;size16&quot;&gt;지금까지 코드형 인프라(IaC)의 도입 배경부터 테라폼 및 AWS CLI 환경 설정 방법까지 살펴보았습니다. 이제 로컬 환경 구축이 완료되었으니 다음 글에서는 실제 .tf 파일 작성법과 terraform init, plan, apply 명령어의 사용법을 자세히 알아보겠습니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;48&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;48&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;48&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;오늘의 한 마디&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;48&quot; data-ke-size=&quot;size16&quot;&gt;최근에 무기력에 대한 영상을 봤는데 거기서 현대인들이 무기력증이 엄청나게 많다고 한다. 그래서 그 무기력증을 해결할 수 있는 방법을 취미라고 했다. 무조건 가만히 쉬는 것을 좋아하는 사람도 있지만 그것이 아니라면 취미를 가지라고 하고 취미에서도 흥미를 느끼지 못한다면 통제 가능한 취미를 가지라고 했다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;48&quot; data-ke-size=&quot;size16&quot;&gt;통제 가능한 취미라는 것이 아래 그림과 같이 밑그림이 그려진 그림에 색칠해서 성공의 기쁨? 완성의 기쁨을 누릴 수 있는 것들을 하라고 했다. 그래서 수학 문제 풀기 이런것도 도움이 되지 않을까 생각했다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;48&quot; data-ke-size=&quot;size16&quot;&gt;아무튼 요즘 세상이 너무 팍팍해서 다들 힘을 못내고 있는 것 같다. 회복 탄력성을 길러 다시 몇 번이고 일어나야 한다. 그래야 생존할 수 있다. 모두 조금 힘들지만 파이팅입니다 ㅎㅎ&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;196&quot; data-origin-height=&quot;148&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XuEzU/dJMcagTUFyy/Ohdu9zhoM0fU6DZdNkFIqK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XuEzU/dJMcagTUFyy/Ohdu9zhoM0fU6DZdNkFIqK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XuEzU/dJMcagTUFyy/Ohdu9zhoM0fU6DZdNkFIqK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXuEzU%2FdJMcagTUFyy%2FOhdu9zhoM0fU6DZdNkFIqK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;196&quot; height=&quot;148&quot; data-origin-width=&quot;196&quot; data-origin-height=&quot;148&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>코딩 개발/AWS</category>
      <category>AWS CLI</category>
      <category>IAC</category>
      <category>IAM</category>
      <category>Terraform</category>
      <author>호소세</author>
      <guid isPermaLink="true">https://pabeba.tistory.com/296</guid>
      <comments>https://pabeba.tistory.com/296#entry296comment</comments>
      <pubDate>Fri, 21 Aug 2026 18:54:48 +0900</pubDate>
    </item>
    <item>
      <title>AWS EC2 에 GitHub Action으로 CI/CD 해보기</title>
      <link>https://pabeba.tistory.com/295</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://pabeba.tistory.com/294&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://pabeba.tistory.com/294&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전 시간에 AWS EC2를 구성하고 파일 업로드와 설정을 손수 진행해보았는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 GitHub Action으로 딸깍 push만 해서 AWS EC2 인스턴스에 파일을 올리고 재시작 하는 것을 해볼겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전전 시간에 deploy.yml 파일에서 업그레이드하고 Github 프로젝트에 설정 조금하면 금방 CI/CD 가능합니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;3&quot; data-ke-size=&quot;size26&quot;&gt;1. CI/CD와 GitHub Actions 개요&lt;/h2&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;본격적인 코드 설명에 앞서 간단한 개념을 잡고 가겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;5&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,0,0&quot;&gt;CI (Continuous Integration - 지속적 통합)&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 개발자들이 작성한 코드를 주기적으로 중앙 저장소에 통합하고,&lt;/span&gt;&lt;span&gt; 자동화된 빌드 및 테스트를 통해 코드의 품질을 검증하는 과정입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,1,0&quot;&gt;CD (Continuous Deployment - 지속적 배포)&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; CI 과정을 통과한 코드를 실제 운영 환경(Production)에 자동으로 배포하는 과정입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,2,0&quot;&gt;GitHub Actions&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; GitHub에서 제공하는 강력한 CI/CD 도구입니다.&lt;/span&gt;&lt;span&gt; GitHub 저장소 내에서 발생하는 이벤트(Push,&lt;/span&gt;&lt;span&gt; Pull Request 등)를 트리거(Trigger)로 삼아 사용자가 정의한 작업(Workflow)을 실행할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-path-to-node=&quot;6&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;6,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,0&quot;&gt;  지식 더하기: 왜 CI/CD를 사용할까요?&lt;/b&gt; CI/CD를 구축하면 개발자는 코드 작성에만 집중할 수 있고, 반복적인 빌드, 테스트, 배포 작업을 자동화하여 &lt;b data-index-in-node=&quot;89&quot; data-path-to-node=&quot;6,0&quot;&gt;휴먼 에러를 방지&lt;/b&gt;하고 &lt;b data-index-in-node=&quot;101&quot; data-path-to-node=&quot;6,0&quot;&gt;배포 속도를 획기적으로 향상&lt;/b&gt;시킬 수 있습니다. 또한, 언제든 안정적으로 배포 가능한 상태를 유지할 수 있다는 큰 장점이 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size26&quot;&gt;2. GitHub Actions 워크플로(Workflow) 분석&lt;/h2&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 실제 배포에 사용되는 &lt;/span&gt;.github/workflows/deploy.yml&lt;span&gt; (파일명은 자유) 파일을 한 부분씩 살펴보며 기능을 설명해 드리겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;전체 소스는 여기 있어요.&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;a href=&quot;https://github.com/hosose/my_project/blob/main/.github/workflows/deploy.yml&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/hosose/my_project/blob/main/.github/workflows/deploy.yml&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1784795662784&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;my_project/.github/workflows/deploy.yml at main &amp;middot; hosose/my_project&quot; data-og-description=&quot;git 사용 연습. Contribute to hosose/my_project development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/hosose/my_project/blob/main/.github/workflows/deploy.yml&quot; data-og-url=&quot;https://github.com/hosose/my_project/blob/main/.github/workflows/deploy.yml&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/HLkZg/dJMb9frSyAE/otRRAUJBcJtv6LrkC8rIk1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/nexHX/dJMb9jOz3RN/5cyHz1kdD2K7adM51x9870/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/hosose/my_project/blob/main/.github/workflows/deploy.yml&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/hosose/my_project/blob/main/.github/workflows/deploy.yml&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/HLkZg/dJMb9frSyAE/otRRAUJBcJtv6LrkC8rIk1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/nexHX/dJMb9jOz3RN/5cyHz1kdD2K7adM51x9870/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;my_project/.github/workflows/deploy.yml at main &amp;middot; hosose/my_project&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;git 사용 연습. Contribute to hosose/my_project development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjUycuZ1OeVAxUAAAAAHQAAAAAQnQ8&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;http&quot;&gt;&lt;code&gt;name: Push 기반 CI/CD 테스트

# [트리거 지정] CI/CD가 작동하게 되는 원인, 이벤트를 정의합니다.
# main 브랜치에서 push 이벤트가 발생(Listen -&amp;gt; on)하면 아래 설정한 내용이 작동합니다.
on:
  push:
    branches:
      - main
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,0,0&quot;&gt;name&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 워크플로의 이름을 지정합니다.&lt;/span&gt;&lt;span&gt; GitHub Actions 탭에서 이 이름으로 표시됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,1,0&quot;&gt;on.push.branches&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 파이프라인을 실행할 트리거를 정의합니다.&lt;/span&gt;&lt;span&gt; 여기서는 &lt;/span&gt;main&lt;span&gt; 브랜치에 코드가 &lt;/span&gt;push&lt;span&gt;될 때만 이 워크플로가 실행되도록 설정했습니다.&lt;/span&gt;&lt;span&gt; 실무에서는 보통 &lt;/span&gt;main&lt;span&gt;(운영) 또는 &lt;/span&gt;develop&lt;span&gt;(개발) 브랜치를 지정합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjUycuZ1OeVAxUAAAAAHQAAAAAQng8&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;# 개별 작업(jobs)을 순서대로 나열합니다 (파이프라인).
jobs:
  # 'ci'라는 이름의 job을 하나 설정합니다.
  ci:
    # 어떤 OS에서 job을 진행할 것인가? -&amp;gt; GitHub에서 클라우드 방식으로 제공합니다 (Runner).
    runs-on: ubuntu-latest
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;14&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,0,0&quot;&gt;jobs&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 워크플로에서 실행될 실제 작업들을 정의합니다.&lt;/span&gt;&lt;span&gt; 여러 작업을 병렬로 실행할 수도 있지만,&lt;/span&gt;&lt;span&gt; 여기서는 &lt;/span&gt;ci&lt;span&gt;라는 하나의 작업을 정의했습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;14,1,0&quot;&gt;runs-on&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 작업이 실행될 가상 환경(Runner)의 OS를 지정합니다.&lt;/span&gt;&lt;span&gt; &lt;/span&gt;ubuntu-latest&lt;span&gt;는 가장 최신의 우분투 환경을 사용하겠다는 의미이며,&lt;/span&gt;&lt;span&gt; GitHub에서 제공하는 클라우드 리소스를 사용하게 됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjUycuZ1OeVAxUAAAAAHQAAAAAQnw8&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;    # 작업 단계(steps)를 지정합니다.
    steps:
      # 1. GitHub에 저장되어 있는 최신 내용을 체크아웃합니다 (소스를 모두 내려받음).
      - name: 코드 checkout
        uses: actions/checkout@v4
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,0,0&quot;&gt;steps&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 하나의 job 내에서 실행될 일련의 단계들을 순서대로 정의합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,1,0&quot;&gt;actions/checkout@v4&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; GitHub에서 공식적으로 제공하는 액션(Action)입니다.&lt;/span&gt;&lt;span&gt; 현재 구동 중인 Runner OS 환경으로 GitHub 저장소의 소스 코드를 복사(Checkout)해옵니다.&lt;/span&gt;&lt;span&gt; 이 단계가 있어야 이후 단계에서 소스 파일을 기반으로 작업을 진행할 수 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjUycuZ1OeVAxUAAAAAHQAAAAAQoA8&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;      # 확인 or 단위테스트 (편의상 생략하고 환경 확인만 진행)
      - name: 확인 검증
        # 여러 개의 명령어를 작동시킬 때는 '|' 기호를 통해 배치로 작성합니다.
        run: |
          pwd
          ls -al
          cat main.py
        shell: bash
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;20&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;20,0,0&quot;&gt;run&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; Runner의 터미널에서 실행할 명령어를 기술합니다.&lt;/span&gt;&lt;span&gt; 여기서는 소스 코드가 정상적으로 체크아웃되었는지 확인하기 위해 현재 경로(&lt;/span&gt;pwd&lt;span&gt;),&lt;/span&gt;&lt;span&gt; 파일 목록(&lt;/span&gt;ls -al&lt;span&gt;),&lt;/span&gt;&lt;span&gt; 그리고 메인 파일 내용(&lt;/span&gt;cat main.py&lt;span&gt;)을 출력해봅니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;실무에서는 이 단계에서 &lt;/span&gt;&lt;b data-index-in-node=&quot;13&quot; data-path-to-node=&quot;20,1,0&quot;&gt;파이썬 패키지 설치(pip install) 및 단위 테스트(pytest 등)를 실행&lt;/b&gt;&lt;span&gt;하여 코드의 이상 유무를 검증하는 CI 과정을 수행합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size20&quot;&gt;  여기서부터는 CD (Continuous Deployment) 작업입니다.&lt;/h4&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 검증된 소스 코드를 실제 운영 중인 AWS EC2 서버로 복사하고 서비스를 재시작하는 배포 과정을 진행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjUycuZ1OeVAxUAAAAAHQAAAAAQoQ8&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;      # [CD 작업 1: 파일 복사]
      # CI 쪽 서버(Runner)에서 EC2 서버(배포용 서버)로 배포 진행 -&amp;gt; SSH 활용
      - name: source code copy to EC2
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.EC2_KEY }}
          port: 22
          # 복사할 대상 (편의상 . (현재 디렉토리 전체))
          source: .
          # 우분투 OS가 세팅된 EC2 서버의 대상 경로로 복사
          target: &quot;/home/ubuntu/projects&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;25&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,0,0&quot;&gt;appleboy/scp-action&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; SCP(Secure Copy) 프로토콜을 이용해 Runner에서 원격 서버로 파일을 복사해주는 서드파이 액션입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,1,0&quot;&gt;with (중요 - 보안)&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; 접속 정보를 입력합니다.&lt;/span&gt;&lt;span&gt; 이때 IP 주소(&lt;/span&gt;HOST&lt;span&gt;),&lt;/span&gt;&lt;span&gt; 사용자명(&lt;/span&gt;USERNAME&lt;span&gt;),&lt;/span&gt;&lt;span&gt; SSH 키(&lt;/span&gt;.pem&lt;span&gt; 파일 내용 - &lt;/span&gt;EC2_KEY&lt;span&gt;)와 같은 민감한 정보는 소스 코드에 직접 노출하지 않고,&lt;/span&gt;&lt;span&gt; GitHub 저장소의 &lt;/span&gt;Settings&lt;span&gt; -&amp;gt; &lt;/span&gt;Secrets and variables&lt;span&gt; -&amp;gt; &lt;/span&gt;Actions&lt;span&gt;에 저장된 &lt;/span&gt;&lt;b data-index-in-node=&quot;183&quot; data-path-to-node=&quot;25,1,0&quot;&gt;Secrets 변수&lt;/b&gt;&lt;span&gt;를 활용해 보안을 유지합니다.&lt;/span&gt;&lt;span&gt; 도커 등에서 사용하는 환경변수(.&lt;/span&gt;&lt;span&gt;env) 파일 내용도 시크릿 변수에 담아 배포 시 동적으로 생성할 수 있습니다.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,2,0&quot;&gt;보안 이슈&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; EC2 서버의 SSH 포트(22번)는 GitHub Action Runner가 접속할 수 있도록 보안 그룹(Security Group)에서 접근 허용이 되어 있어야 합니다.&lt;/span&gt;&lt;span&gt; 편의상 &lt;/span&gt;0.0.0.0/0&lt;span&gt; (모든 IP 허용)으로 설정하기도 하지만,&lt;/span&gt;&lt;span&gt; 보안 강화를 위해 GitHub의 서브넷 IP만 허용하는 방식이 더 권장됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1583&quot; data-origin-height=&quot;873&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yyNvz/dJMb998f9Xt/8gcy3DCgc2Z6Oau1XYXSXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yyNvz/dJMb998f9Xt/8gcy3DCgc2Z6Oau1XYXSXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yyNvz/dJMb998f9Xt/8gcy3DCgc2Z6Oau1XYXSXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyyNvz%2FdJMb998f9Xt%2F8gcy3DCgc2Z6Oau1XYXSXk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1583&quot; height=&quot;873&quot; data-origin-width=&quot;1583&quot; data-origin-height=&quot;873&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1624&quot; data-origin-height=&quot;345&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bn0xAO/dJMcaiqARR2/aKf9QkyOm5ki8jOtDZfix0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bn0xAO/dJMcaiqARR2/aKf9QkyOm5ki8jOtDZfix0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bn0xAO/dJMcaiqARR2/aKf9QkyOm5ki8jOtDZfix0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbn0xAO%2FdJMcaiqARR2%2FaKf9QkyOm5ki8jOtDZfix0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1624&quot; height=&quot;345&quot; data-origin-width=&quot;1624&quot; data-origin-height=&quot;345&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjUycuZ1OeVAxUAAAAAHQAAAAAQog8&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;      # [CD 작업 2: 서비스 재가동]
      # 파일 복사 후 서버에서 실제 서비스를 갱신하고 재시작하는 명령을 전달합니다.
      - name: Run Script And Service Restart
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.EC2_KEY }}
          port: 22
          script: |
            # 1. 프로젝트 폴더 위치로 이동합니다.
            #cd /home/ubuntu/projects
            
            # 2. 가상환경에 추가된 패키지가 있다면 설치를 진행합니다.
            #./web/bin/pip install -r requirements.txt
            
            # 3. systemd로 관리 중인 애플리케이션 서비스를 재시작합니다.
            sudo systemctl restart hello.service
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;28&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;28,0,0&quot;&gt;appleboy/ssh-action&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; SSH를 통해 원격 서버에 접속하여 명령어를 실행해주는 액션입니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;28,1,0&quot;&gt;script&lt;/b&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; EC2 서버에 접속해서 실행할 쉘 명령어를 기술합니다.&lt;/span&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;28,1,1&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span&gt;배포된 폴더로 이동합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;새로 추가된 파이썬 패키지가 있다면 가상환경의 pip를 이용해 설치합니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;리눅스 시스템 데몬(&lt;/span&gt;systemd&lt;span&gt;)으로 관리 중인 웹 애플리케이션 서비스(&lt;/span&gt;hello.service&lt;span&gt;)를 재시작하여 변경된 코드가 반영되도록 합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-path-to-node=&quot;29&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;29,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,0&quot;&gt;  지식 더하기: 보안 이슈에 대한 첨언&lt;/b&gt; 원문의 주석에 &quot;EC2 -&amp;gt; GitHub로 다시 요청 보내서 명령 실행(이 부분은 보안 이슈로 하지 않고 터미널에서 수동으로 함)&quot;이라는 내용이 있는데, 이는 GitHub Actions의 동작 방식과 다소 차이가 있습니다. GitHub Actions는 **GitHub 측(Runner)에서 EC2로 접속하는 형태(Outbound)**이지, EC2가 GitHub에 요청을 보내는 구조가 아닙니다. 위 워크플로처럼 SSH 액션을 사용하면 GitHub 측에서 EC2에 접속해 명령어를 실행할 수 있어 &lt;b data-index-in-node=&quot;301&quot; data-path-to-node=&quot;29,0&quot;&gt;완전한 자동화 배포가 가능&lt;/b&gt;합니다. 다만, 민감한 키(secrets.EC2_KEY)가 GitHub 측에 저장된다는 점에 대한 보안 관리(예: 주기적인 키 로테이션, 권한 최소화)가 필요합니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h3 data-path-to-node=&quot;31&quot; data-ke-size=&quot;size23&quot;&gt;3. 마치며&lt;/h3&gt;
&lt;p data-path-to-node=&quot;32&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이제 모든 설정이 완료되었습니다.&lt;/span&gt;&lt;span&gt; &lt;/span&gt;main&lt;span&gt; 브랜치에 코드를 &lt;/span&gt;push&lt;span&gt;하면 GitHub Actions가 자동으로 동작하여 코드 체크아웃 -&amp;gt; 검증(테스트 생략) -&amp;gt; EC2 파일 복사 -&amp;gt; 서비스 재시작까지 한 번에 완료해 줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;32&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;33&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;이렇게 구축된 CI/CD 파이프라인은 초기 세팅에 노력이 들지만,&lt;/span&gt;&lt;span&gt; 이후 개발 생산성을 비약적으로 높여주는 강력한 도구가 됩니다.&lt;/span&gt;&lt;span&gt; 여러분의 프로젝트에도 꼭 적용해 보시길 권장합니다!&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>코딩 개발/Git</category>
      <category>AWS</category>
      <category>CD</category>
      <category>CI</category>
      <category>CI/CD</category>
      <category>deploy.yml</category>
      <category>EC2</category>
      <category>git</category>
      <category>github</category>
      <category>github action</category>
      <author>호소세</author>
      <guid isPermaLink="true">https://pabeba.tistory.com/295</guid>
      <comments>https://pabeba.tistory.com/295#entry295comment</comments>
      <pubDate>Thu, 20 Aug 2026 18:40:40 +0900</pubDate>
    </item>
    <item>
      <title>AWS - EC2 서버 구성 및 직접 app 배포 해보기 (CI/CD가 왜 좋은지 이유를 알기 위한 탐...)</title>
      <link>https://pabeba.tistory.com/294</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;고민 많이 했습니다. EC2 서버 만드는 과정을 블로그에 작성해야한다는 엄청난 중압감 하지만 사나이라면 이겨내야한다고 생각합니다. 그냥 해보겠습니다. ㅋ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;이번시간은 AWS EC2 인스턴스에 직접 접속하여 파이썬 개발 환경을 구축하고,&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;50&quot; data-path-to-node=&quot;4&quot;&gt;FastAPI 애플리케이션을 백그라운드 데몬 서비스(systemd)로 등록하여 안정적으로 배포하는 전체 과정&lt;/b&gt;을 정리해보겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size26&quot;&gt;1. 수동 서버/프로덕션 환경 구성의 단점과 한계&lt;/h2&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;클라우드 인프라 구축 시 Terraform이나 Docker/Kubernetes 같은 자동화 도구 없이, EC2에 직접 접속하여 하나씩 세팅하는 방식은 다음과 같은 명확한 한계가 존재합니다. (이 단점을 보여드리기 위한 내용)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;8&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,0,0&quot;&gt;시간 소요 및 휴먼 에러(Human Error) 가능성 증가&lt;/b&gt;: 설치 명령어나 환경변수를 하나라도 누락하면 원인을 찾기 어려운 오류가 발생할 수 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,1,0&quot;&gt;재현성(Reproducibility)의 한계&lt;/b&gt;: 패키지 버전 업데이트나 리눅스 환경 변수로 인해 '어제는 되었는데 오늘은 안 되는' 상황이 발생하기 쉽습니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,2,0&quot;&gt;결론&lt;/b&gt;: 수동 구축은 초기 인프라 구조를 이해하는 데는 가장 좋지만, 실제 운영에서는 CI/CD 파이프라인이나 컨테이너 기반 자동화 배포 환경으로 전환하는 것이 바람직합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size26&quot;&gt;2. EC2 초기 접속 및 인프라 사전 준비&lt;/h2&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,0,0&quot;&gt;1. AWS 콘솔 접속&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;할당받은 로그인 주소를 통해 콘솔에 접속합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;449&quot; data-origin-height=&quot;606&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cqtG7q/dJMcabZopsG/1bS3z81TAheXk9E2JaSIKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cqtG7q/dJMcabZopsG/1bS3z81TAheXk9E2JaSIKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cqtG7q/dJMcabZopsG/1bS3z81TAheXk9E2JaSIKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcqtG7q%2FdJMcabZopsG%2F1bS3z81TAheXk9E2JaSIKK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;449&quot; height=&quot;606&quot; data-origin-width=&quot;449&quot; data-origin-height=&quot;606&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,1,0&quot;&gt;2. 보안 그룹(Security Group) 설정 + 태그 추가&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인바운드 규칙에 SSH 접속용 22번 포트와 FastAPI 웹 서비스 연결용 8000번 포트를 개방합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;태그 추가하면 검색할 때 쉬워용&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1019&quot; data-origin-height=&quot;425&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cCvbZ4/dJMcaa7f2Nu/syTXRgLdkITHTY6H54BZxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cCvbZ4/dJMcaa7f2Nu/syTXRgLdkITHTY6H54BZxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cCvbZ4/dJMcaa7f2Nu/syTXRgLdkITHTY6H54BZxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcCvbZ4%2FdJMcaa7f2Nu%2FsyTXRgLdkITHTY6H54BZxk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1019&quot; height=&quot;425&quot; data-origin-width=&quot;1019&quot; data-origin-height=&quot;425&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1375&quot; data-origin-height=&quot;388&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kCi4B/dJMcaftSzdd/2vlXgkrcpp1HaEBHMMVeQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kCi4B/dJMcaftSzdd/2vlXgkrcpp1HaEBHMMVeQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kCi4B/dJMcaftSzdd/2vlXgkrcpp1HaEBHMMVeQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkCi4B%2FdJMcaftSzdd%2F2vlXgkrcpp1HaEBHMMVeQK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1375&quot; height=&quot;388&quot; data-origin-width=&quot;1375&quot; data-origin-height=&quot;388&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1418&quot; data-origin-height=&quot;285&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJ5I0f/dJMcabSwIph/sQGI5pKgnFF4pwuEei4ud0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJ5I0f/dJMcabSwIph/sQGI5pKgnFF4pwuEei4ud0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJ5I0f/dJMcabSwIph/sQGI5pKgnFF4pwuEei4ud0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJ5I0f%2FdJMcabSwIph%2FsQGI5pKgnFF4pwuEei4ud0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1418&quot; height=&quot;285&quot; data-origin-width=&quot;1418&quot; data-origin-height=&quot;285&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,2,0&quot;&gt;3. 퍼블릭 IP 및 Elastic IP(탄력적 IP) 할당&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EC2 인스턴스를 재부팅할 때마다 퍼블릭 IP가 변경되는 것을 방지하기 위해 전용 탄력적 IP를 할당받아 매핑합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1378&quot; data-origin-height=&quot;606&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1EEBp/dJMcacxbedF/a22N7mQApvKKO8A8BEmQq1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1EEBp/dJMcacxbedF/a22N7mQApvKKO8A8BEmQq1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1EEBp/dJMcacxbedF/a22N7mQApvKKO8A8BEmQq1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1EEBp%2FdJMcacxbedF%2Fa22N7mQApvKKO8A8BEmQq1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1378&quot; height=&quot;606&quot; data-origin-width=&quot;1378&quot; data-origin-height=&quot;606&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,3,0&quot;&gt;4. 인스턴스 생성&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1112&quot; data-origin-height=&quot;659&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csThMH/dJMcabkM8TF/KjXt1SNk67l8TnS2KaxiwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csThMH/dJMcabkM8TF/KjXt1SNk67l8TnS2KaxiwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csThMH/dJMcabkM8TF/KjXt1SNk67l8TnS2KaxiwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsThMH%2FdJMcabkM8TF%2FKjXt1SNk67l8TnS2KaxiwK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1112&quot; height=&quot;659&quot; data-origin-width=&quot;1112&quot; data-origin-height=&quot;659&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;aws ec2 에 작성해야하는 내용은 영어로 작성해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희는 ubuntu를 이용했고 대부분의 설정은 기본 값을 그대로 해주시고 제가 사진 올린것만 변경하시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1104&quot; data-origin-height=&quot;408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/o2ooE/dJMcaidafPM/CRajdiGGSV1lDFjKhzvNh1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/o2ooE/dJMcaidafPM/CRajdiGGSV1lDFjKhzvNh1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/o2ooE/dJMcaidafPM/CRajdiGGSV1lDFjKhzvNh1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fo2ooE%2FdJMcaidafPM%2FCRajdiGGSV1lDFjKhzvNh1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1104&quot; height=&quot;408&quot; data-origin-width=&quot;1104&quot; data-origin-height=&quot;408&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;키 페어 만드는 것이 매우 중요합니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;키페어 만들기&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;550&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s1Gzq/dJMcaiYmB4g/pTveVyiOX5AMiYXwjvTBd0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s1Gzq/dJMcaiYmB4g/pTveVyiOX5AMiYXwjvTBd0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s1Gzq/dJMcaiYmB4g/pTveVyiOX5AMiYXwjvTBd0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs1Gzq%2FdJMcaiYmB4g%2FpTveVyiOX5AMiYXwjvTBd0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;592&quot; height=&quot;550&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;550&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘 만들어서 어디 꽁꽁 숨겨두세요. 해킹당하시지 않게 ㅎㅎ&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1093&quot; data-origin-height=&quot;441&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/5NduB/dJMcahZvrAN/P1mGdZ8gltvGwgQrBBzlGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/5NduB/dJMcahZvrAN/P1mGdZ8gltvGwgQrBBzlGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/5NduB/dJMcahZvrAN/P1mGdZ8gltvGwgQrBBzlGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F5NduB%2FdJMcahZvrAN%2FP1mGdZ8gltvGwgQrBBzlGK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1093&quot; height=&quot;441&quot; data-origin-width=&quot;1093&quot; data-origin-height=&quot;441&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1099&quot; data-origin-height=&quot;238&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnfeSH/dJMcagzyf0B/9KWGvaDyfSKVcx3qfA1obk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnfeSH/dJMcagzyf0B/9KWGvaDyfSKVcx3qfA1obk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnfeSH/dJMcagzyf0B/9KWGvaDyfSKVcx3qfA1obk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnfeSH%2FdJMcagzyf0B%2F9KWGvaDyfSKVcx3qfA1obk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1099&quot; height=&quot;238&quot; data-origin-width=&quot;1099&quot; data-origin-height=&quot;238&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;529&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/W0x19/dJMcajbUBHz/ZhT0lMaVk9Mggb0xDTYR2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/W0x19/dJMcajbUBHz/ZhT0lMaVk9Mggb0xDTYR2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/W0x19/dJMcajbUBHz/ZhT0lMaVk9Mggb0xDTYR2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FW0x19%2FdJMcajbUBHz%2FZhT0lMaVk9Mggb0xDTYR2k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;542&quot; height=&quot;529&quot; data-origin-width=&quot;542&quot; data-origin-height=&quot;529&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정 다 하시고 인스턴스 시작 누르시면 인스턴스 시작됩니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,3,0&quot;&gt;5. SSH 접속&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널이나 SSH 툴(PuTTY, MobaXterm 등)을 열고 퍼블릭 IP와 .pem 키를 이용해 서버에 접근합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;MobaXterm 설치 위치&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://mobaxterm.mobatek.net/download-home-edition.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://mobaxterm.mobatek.net/download-home-edition.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1784792120328&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;MobaXterm free Xserver and tabbed SSH client for Windows&quot; data-og-description=&quot;The ultimate toolbox for remote computing - includes X server, enhanced SSH client and much more!&quot; data-og-host=&quot;mobaxterm.mobatek.net&quot; data-og-source-url=&quot;https://mobaxterm.mobatek.net/download-home-edition.html&quot; data-og-url=&quot;https://mobaxterm.mobatek.net/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/D7WxK/dJMb83kGldA/sUiJi0Ed6pr21596Ynzpx0/img.png?width=764&amp;amp;height=489&amp;amp;face=0_0_764_489,https://scrap.kakaocdn.net/dn/p1gkt/dJMb887l3i4/sTGqfnrKI2EeBMdowV4z70/img.png?width=768&amp;amp;height=443&amp;amp;face=0_0_768_443,https://scrap.kakaocdn.net/dn/n64xC/dJMb9bwfpoU/rmk7M8w2ZbGzs9Xn4aJCF0/img.png?width=768&amp;amp;height=443&amp;amp;face=0_0_768_443&quot;&gt;&lt;a href=&quot;https://mobaxterm.mobatek.net/download-home-edition.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://mobaxterm.mobatek.net/download-home-edition.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/D7WxK/dJMb83kGldA/sUiJi0Ed6pr21596Ynzpx0/img.png?width=764&amp;amp;height=489&amp;amp;face=0_0_764_489,https://scrap.kakaocdn.net/dn/p1gkt/dJMb887l3i4/sTGqfnrKI2EeBMdowV4z70/img.png?width=768&amp;amp;height=443&amp;amp;face=0_0_768_443,https://scrap.kakaocdn.net/dn/n64xC/dJMb9bwfpoU/rmk7M8w2ZbGzs9Xn4aJCF0/img.png?width=768&amp;amp;height=443&amp;amp;face=0_0_768_443');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;MobaXterm free Xserver and tabbed SSH client for Windows&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;The ultimate toolbox for remote computing - includes X server, enhanced SSH client and much more!&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;mobaxterm.mobatek.net&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치후 실행&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Session 버튼 클릭&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSH 클릭&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1011&quot; data-origin-height=&quot;671&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nCISi/dJMcabdSbuu/vVAB3RXcjReSjUhzWJOb2k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nCISi/dJMcabdSbuu/vVAB3RXcjReSjUhzWJOb2k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nCISi/dJMcabdSbuu/vVAB3RXcjReSjUhzWJOb2k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnCISi%2FdJMcabdSbuu%2FvVAB3RXcjReSjUhzWJOb2k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1011&quot; height=&quot;671&quot; data-origin-width=&quot;1011&quot; data-origin-height=&quot;671&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Remote host 값을 EC2 인스턴스에서 가져옵니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Username 은 ubuntu 입니다. (default 값이라고 하네요 ㅎㅎ)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저장했던 pem 키는 Use private key에 업로드해주면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1257&quot; data-origin-height=&quot;598&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXsHvD/dJMcaazoqf1/Cq4wkSQo5ZW9Y6qYyK3kR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXsHvD/dJMcaazoqf1/Cq4wkSQo5ZW9Y6qYyK3kR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXsHvD/dJMcaazoqf1/Cq4wkSQo5ZW9Y6qYyK3kR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXsHvD%2FdJMcaazoqf1%2FCq4wkSQo5ZW9Y6qYyK3kR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1257&quot; height=&quot;598&quot; data-origin-width=&quot;1257&quot; data-origin-height=&quot;598&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다 하시고 ok 누르시면 접속되실 겁니다. 아마 무슨 창이 뜰텐데 accept 해주시면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안되면 조금 상세히 뭐가 안되시는지 댓글 남겨주세요 ㅎㅎㅎ&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size26&quot;&gt;3. 리눅스 패키지 및 파이썬 가상환경(venv) 세팅&lt;/h2&gt;
&lt;h3 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size23&quot;&gt;1) 시스템 패키지 업데이트&lt;/h3&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjUycuZ1OeVAxUAAAAAHQAAAAAQ4Q4&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt upgrade -y
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-path-to-node=&quot;16&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;16,0&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b data-index-in-node=&quot;3&quot; data-path-to-node=&quot;16,0&quot;&gt;알아두면 좋은 리눅스 지식: apt vs apt-get&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,0,0&quot;&gt;apt&lt;/b&gt;: apt-get과 apt-cache의 주요 기능을 통합하여 일반 사용자가 사용하기 쉽도록 만든 최신 명령어로, 진행률 표시줄 및 권장 패키지 안내 등이 개선되어 대화형 터미널에 적합합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,1,0&quot;&gt;apt-get&lt;/b&gt;: 하위 호환성을 보장하는 오래된 명령어입니다. 동작 결과가 일정하여 쉘 스크립트 기반 자동화 작업 시 안전하게 자주 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size23&quot;&gt;2) 파이썬 pip 및 venv 설치&lt;/h3&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjUycuZ1OeVAxUAAAAAHQAAAAAQ4g4&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;sudo apt install python3-pip python3-venv -y
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-path-to-node=&quot;19&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;19,0&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b data-index-in-node=&quot;3&quot; data-path-to-node=&quot;19,0&quot;&gt;왜 파이썬 가상환경(venv)을 사용할까요?&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;19,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 OS 환경에서 여러 파이썬 프로젝트를 구동할 때, 프로젝트 간 라이브러리 패키지 버전 충돌을 방지하고 격리된 독립 환경을 만들어 줍니다.&lt;/li&gt;
&lt;li&gt;&lt;i data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,1,1,0&quot;&gt;참고: 도커(Docker) 컨테이너 환경에서는 1개의 컨테이너 OS 단위에 단 하나의 애플리케이션만 구동되므로, 컨테이너 내부에서는 가상환경을 별도로 생성하지 않는 경우가 많습니다.&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size23&quot;&gt;3) 프로젝트 생성 및 패키지 설치&lt;/h3&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjUycuZ1OeVAxUAAAAAHQAAAAAQ4w4&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# 프로젝트 디렉토리 생성 및 이동
mkdir projects &amp;amp;&amp;amp; cd projects

# 'web'이라는 이름의 가상환경 생성
python3 -m venv web

# 가상환경 활성화 (프롬프트 앞에 (web) 표시 확인)
source web/bin/activate

# 가상환경 내 pip 최신화
pip install --upgrade pip

# 백엔드 필수 패키지 설치
pip install fastapi uvicorn[standard] jinja2
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;이후 소스 코드(main.py 등)를 SFTP 전송, Git Clone, 혹은 신규 작성을 통해 ~/projects/ 디렉토리에 배치합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;24&quot; data-ke-size=&quot;size26&quot;&gt;4. 백그라운드 서비스를 위한 systemd 파일 구성&lt;/h2&gt;
&lt;p data-path-to-node=&quot;25&quot; data-ke-size=&quot;size16&quot;&gt;터미널 세션을 종료하더라도 서버가 계속해서 실행되고, EC2 인스턴스가 재가동되더라도 서비스가 자동으로 켜지도록 리눅스 시스템 데몬 서비스(systemd)로 등록해 주어야 합니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;26&quot; data-ke-size=&quot;size23&quot;&gt;1) 서비스 등록 파일 생성&lt;/h3&gt;
&lt;p data-path-to-node=&quot;27&quot; data-ke-size=&quot;size16&quot;&gt;/etc/systemd/system/ 디렉토리 내의 모든 파일은 root 권한 소유이므로, sudo 명령어를 활용하여 관리자 권한으로 작성합니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjUycuZ1OeVAxUAAAAAHQAAAAAQ5A4&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;awk&quot;&gt;&lt;code&gt;sudo nano /etc/systemd/system/hello.service
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;29&quot; data-ke-size=&quot;size23&quot;&gt;2) 서비스 설정 내용 기재&lt;/h3&gt;
&lt;p data-path-to-node=&quot;30&quot; data-ke-size=&quot;size16&quot;&gt;아래 내용을 편집기에 그대로 입력합니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjUycuZ1OeVAxUAAAAAHQAAAAAQ5Q4&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;[Unit]
Description=FastAPI WAS (Web Application Service)
After=network.target

[Service]
User=ubuntu
Group=www-data
# 애플리케이션 소스 코드가 위치한 작업 디렉토리
WorkingDirectory=/home/ubuntu/projects

# 환경변수 파일(.env)이 필요하다면 아래 주석 해제 후 연결
# EnvironmentFile=/home/ubuntu/projects/.env

# 가상환경(web) 내부에 설치된 uvicorn으로 FastAPI 앱 실행
ExecStart=/home/ubuntu/projects/web/bin/uvicorn main:app --host 0.0.0.0 --port 8000

# 프로세스가 다운되거나 OS 재부팅 시 항상 자동 재가동
Restart=always

[Install]
WantedBy=multi-user.target
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;32&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;32,0,0&quot;&gt;저장 및 종료 방법&lt;/b&gt;: Ctrl + X ➔ Y 입력 ➔ Enter&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;34&quot; data-ke-size=&quot;size26&quot;&gt;5. 서비스 등록 및 제어&lt;/h2&gt;
&lt;p data-path-to-node=&quot;35&quot; data-ke-size=&quot;size16&quot;&gt;작성한 서비스 파일을 시스템에 반영하고 제어합니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjUycuZ1OeVAxUAAAAAHQAAAAAQ5g4&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# 1. systemd 데몬 재로드 (새로 작성된 서비스 파일 인식)
sudo systemctl daemon-reload

# 2. 서비스 상태 확인 (초기 상태: inactive)
sudo systemctl status hello.service

# 3. 서비스 시작
sudo systemctl start hello.service

# 4. 서버(OS) 재부팅 시 서비스가 자동으로 실행되도록 설정
sudo systemctl enable hello.service
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwjUycuZ1OeVAxUAAAAAHQAAAAAQ5w4&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;# 실행 정상 상태 확인 예시
● hello.service - FastAPI WAS (Web Application Service)
     Loaded: loaded (/etc/systemd/system/hello.service; enabled; preset: enabled)
     Active: active (running) since Thu 2026-07-23 02:12:42 UTC; 8s ago
   Main PID: 50681 (uvicorn)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;38&quot; data-ke-size=&quot;size23&quot;&gt;  서비스 관리 주요 명령어 요약&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;39&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;39,0,0&quot;&gt;중단&lt;/b&gt;: sudo systemctl stop hello.service&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;39,1,0&quot;&gt;재가동&lt;/b&gt;: sudo systemctl restart hello.service&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;39,2,0&quot;&gt;상태 확인&lt;/b&gt;: sudo systemctl status hello.service&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;41&quot; data-ke-size=&quot;size26&quot;&gt;6. 최종 배포 테스트&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;42&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;42,0,0&quot;&gt;터미널 세션 종료 테스트&lt;/b&gt;: SSH 터미널 접속을 종료한 후에도 웹 브라우저에서 http://[EC2-퍼블릭IP]:8000으로 정상 접속되는지 확인합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;42,1,0&quot;&gt;인스턴스 재부팅 테스트&lt;/b&gt;: AWS 콘솔에서 EC2 인스턴스를 재시작(Reboot)한 뒤에도 systemd에 의해 FastAPI 서비스가 자동으로 로드되어 정상 응답하는지 테스트합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-path-to-node=&quot;43&quot; data-ke-size=&quot;size16&quot;&gt;이로써 EC2 환경에 FastAPI 애플리케이션 수동 배포 및 자동 재시작 환경 세팅이 모두 완료되었습니다! 추후에는 이 환경에 GitHub Actions나 Jenkins를 연동하여 CI/CD 파이프라인으로 발전시킬 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-path-to-node=&quot;43&quot; data-ke-size=&quot;size16&quot;&gt;아 그리고 소스 코드가 필요하시다면 여기서 사용하세요.&lt;/p&gt;
&lt;p data-path-to-node=&quot;43&quot; data-ke-size=&quot;size16&quot;&gt;main branch에 있는 소스 사용하시면 됩니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;43&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;43&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/hosose/my_project&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/hosose/my_project&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1784793338643&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - hosose/my_project: git 사용 연습&quot; data-og-description=&quot;git 사용 연습. Contribute to hosose/my_project development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/hosose/my_project&quot; data-og-url=&quot;https://github.com/hosose/my_project&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/d0IlmX/dJMb9lMoCF2/LN2cIvscpxEVMNZvx9Mmv0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/sV4Xd/dJMb81f5Ulj/qLcHwul3L7H0rEl5hHniK1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/hosose/my_project&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/hosose/my_project&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/d0IlmX/dJMb9lMoCF2/LN2cIvscpxEVMNZvx9Mmv0/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600,https://scrap.kakaocdn.net/dn/sV4Xd/dJMb81f5Ulj/qLcHwul3L7H0rEl5hHniK1/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - hosose/my_project: git 사용 연습&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;git 사용 연습. Contribute to hosose/my_project development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아무튼 위의 작업을 자동화하여 직접 수동으로 터미널에 작성하지 않게 하기 위해 CI/CD를 반드시 해야합니다! 너무 귀찮거덩요.&lt;/p&gt;</description>
      <category>코딩 개발/AWS</category>
      <category>AWS</category>
      <category>CD</category>
      <category>CI</category>
      <category>EC2</category>
      <category>보안규칙</category>
      <author>호소세</author>
      <guid isPermaLink="true">https://pabeba.tistory.com/294</guid>
      <comments>https://pabeba.tistory.com/294#entry294comment</comments>
      <pubDate>Wed, 19 Aug 2026 18:23:39 +0900</pubDate>
    </item>
    <item>
      <title>GitHub Actions - CI/CD (./github/workflow/deploy.yml)</title>
      <link>https://pabeba.tistory.com/293</link>
      <description>&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;이번 시간에는 현대 소프트웨어 개발 및 DevOps 환경에서 필수 요소로 자리 잡은 CI/CD(지속적 통합 및 지속적 배포)의 개념과 배포 모델(Push vs Pull), 그리고 &lt;b data-index-in-node=&quot;103&quot; data-path-to-node=&quot;4&quot;&gt;GitHub Actions&lt;/b&gt;를 활용하여 AWS EC2 인스턴스에 코드를 자동으로 배포하는 실습까지 한눈에 알기 쉽게 정리해 보겠습니다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size26&quot;&gt;1. CI/CD 개요 및 필요성&lt;/h2&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;  CI/CD란?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;8&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,0,0&quot;&gt;CI (Continuous Integration, 지속적 통합)&lt;/b&gt;: 개발자들이 작업한 소스 코드를 주기적으로 중앙 저장소에 자동 합치고, 이를 검증하기 위해 &lt;b data-index-in-node=&quot;87&quot; data-path-to-node=&quot;8,0,0&quot;&gt;자동화된 빌드 및 테스트&lt;/b&gt;를 수행하는 프로세스입니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,1,0&quot;&gt;CD (Continuous Delivery / Deployment, 지속적 제공 / 배포)&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;8,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,1,1,0,0&quot;&gt;Continuous Delivery&lt;/b&gt;: CI 통과 후 프로덕션 환경에 배포할 수 있도록 준비(릴리스)하는 과정입니다. (최종 배포 버튼은 사람이 클릭)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;8,1,1,1,0&quot;&gt;Continuous Deployment&lt;/b&gt;: CI를 통과한 코드를 사람이 개입하지 않고 &lt;b data-index-in-node=&quot;47&quot; data-path-to-node=&quot;8,1,1,1,0&quot;&gt;실제 프로덕션 서버에 자동으로 배포&lt;/b&gt;하는 완벽 자동화 과정입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size23&quot;&gt;  CI/CD 도입 시 이점&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,0,0&quot;&gt;개발 라이프사이클 단축&lt;/b&gt;: 코드 작성 후 배포까지 걸리는 수동 작업 시간을 획기적으로 줄여줍니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,1,0&quot;&gt;안정성 및 소프트웨어 품질 향상&lt;/b&gt;: 커밋마다 자동 테스트가 실행되므로 버그와 코드 충돌을 빠르게 감지합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;10,2,0&quot;&gt;생산성 증가 및 비용 절감&lt;/b&gt;: 반복적인 배포 작업이 자동화되어 개발자가 비즈니스 로직 작성에만 집중할 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size26&quot;&gt;2. CI/CD 배포 모델 (Push vs Pull)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;배포 방식은 크게 Push 방식(전통적 방식)과 Pull 방식(GitOps 방식)으로 나누어 볼 수 있습니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQxRo&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;gcode&quot;&gt;&lt;code&gt;[ Push 모델 ]
  GitHub (CI) ─────SSH 접속/파일전송(Push)─────&amp;gt;  AWS EC2 (운영서버)

[ Pull 모델 (GitOps) ]
  GitHub (CI) ──(Manifest 변경)──&amp;gt; Git Repo &amp;lt;──주기적 감지/가져오기(Pull)── ArgoCD (클러스터 내부)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size23&quot;&gt;1) Push 모델 (전통적 방식)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,0,0&quot;&gt;정의&lt;/b&gt;: CI 서버(GitHub Actions, Jenkins 등)가 빌드/테스트를 완료한 후, &lt;b data-index-in-node=&quot;53&quot; data-path-to-node=&quot;16,0,0&quot;&gt;직접 원격 서버(AWS EC2 등)에 접속(SSH)하여 배포 명령을 밀어넣는(Push)&lt;/b&gt; 방식입니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,0&quot;&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;16,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 파이프라인 안에서 [빌드 ➔ 테스트 ➔ 배포]를 일괄적으로 직관 처리할 수 있습니다.&lt;/li&gt;
&lt;li&gt;구성이 매우 간단하여 소규모 프로젝트나 단일 서버 환경에 적합합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;16,1,1,2,0&quot;&gt;주의점&lt;/b&gt;: CI 서버가 운영 서버의 접근 권한(SSH Key, IP 정보 등)을 들고 있어야 하므로, CI 서버가 해킹당할 경우 보안 위험이 발생할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size23&quot;&gt;2) Pull 모델 (GitOps 방식)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;18&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,0,0&quot;&gt;정의&lt;/b&gt;: 배포 서버 내부의 에이전트(ArgoCD 등)가 Git 저장소를 주기적으로 모니터링하다가 &lt;b data-index-in-node=&quot;53&quot; data-path-to-node=&quot;18,0,0&quot;&gt;새로운 변경 사항(Manifest)이 생기면 스스로 가져와(Pull) 적용&lt;/b&gt;하는 방식입니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;18,1,0&quot;&gt;특징&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;18,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;CI 서버가 운영 환경에 직접 접근하지 않으므로 &lt;b data-index-in-node=&quot;27&quot; data-path-to-node=&quot;18,1,1,0,0&quot;&gt;보안상 매우 유리&lt;/b&gt;합니다.&lt;/li&gt;
&lt;li&gt;쿠버네티스(Kubernetes) 환경에서 버전 관리 및 선언적 배포(Declarative Deployment) 관리가 수월합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-path-to-node=&quot;19&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;19,0&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b data-index-in-node=&quot;3&quot; data-path-to-node=&quot;19,0&quot;&gt;Tip&lt;/b&gt;: 단일 EC2에 소규모 서비스를 배포할 때는 Push 모델(GitHub Actions + SSH)이 훨씬 간단하고 효율적입니다. 반면, 쿠버네티스 기반의 클러스터 환경에서는 Push(CI) + Pull(CD via ArgoCD)을 조합하는 것이 현대적인 대세 패턴입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;21&quot; data-ke-size=&quot;size26&quot;&gt;3. [실습] GitHub Actions를 이용한 Push 기반 CI/CD 구축&lt;/h2&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;이제 GitHub Actions를 이용해 소스 코드가 main 브랜치에 push되면,&lt;/p&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;AWS EC2 서버로 소스 코드가 자동 전송되는 파이프라인을 만들어 보겠습니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;23&quot; data-ke-size=&quot;size23&quot;&gt;1) 프로젝트 구조 준비&lt;/h3&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;우선 아래와 같이 파이썬(FastAPI 또는 Flask) 프로젝트가 구성되어 있다고 가정합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;25&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;main.py&lt;/li&gt;
&lt;li&gt;templates/index.html&lt;/li&gt;
&lt;li&gt;static/&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;381&quot; data-origin-height=&quot;140&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bNLY4c/dJMcacqrHDm/QsQOX5Hd3d4KrfKKGVR1H1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bNLY4c/dJMcacqrHDm/QsQOX5Hd3d4KrfKKGVR1H1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bNLY4c/dJMcacqrHDm/QsQOX5Hd3d4KrfKKGVR1H1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbNLY4c%2FdJMcacqrHDm%2FQsQOX5Hd3d4KrfKKGVR1H1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;381&quot; height=&quot;140&quot; data-origin-width=&quot;381&quot; data-origin-height=&quot;140&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;26&quot; data-ke-size=&quot;size16&quot;&gt;GitHub Actions를 발동시키려면 프로젝트 루트 디렉토리에 &lt;b data-index-in-node=&quot;37&quot; data-path-to-node=&quot;26&quot;&gt;.github/workflows/&lt;/b&gt; 폴더를 만들고 YAML 파일(예: deploy.yml)을 작성해야 합니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;27&quot; data-ke-size=&quot;size23&quot;&gt;2) 사전 작업: GitHub Secrets 환경 변수 등록&lt;/h3&gt;
&lt;p data-path-to-node=&quot;28&quot; data-ke-size=&quot;size16&quot;&gt;SSH 접속 정보와 비밀키를 소스 코드(YML)에 직접 하드코딩하면 보안상 치명적입니다. GitHub 저장소의 &lt;b data-index-in-node=&quot;62&quot; data-path-to-node=&quot;28&quot;&gt;Settings ➔ Secrets and variables ➔ Actions&lt;/b&gt;로 이동하여 다음 비밀값들을 등록해 줍니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;29&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;HOST: AWS EC2 퍼블릭 IP 주소 (또는 도메인)&lt;/li&gt;
&lt;li&gt;USERNAME: EC2 OS 사용자 이름 (Ubuntu의 경우 기본값 ubuntu)&lt;/li&gt;
&lt;li&gt;EC2_KEY: EC2 인스턴스 생성 시 받은 .pem 파일의 전체 텍스트 내용&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;31&quot; data-ke-size=&quot;size23&quot;&gt;3) GitHub Actions 워크플로우 파일 작성 (.github/workflows/deploy.yml)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;32&quot; data-ke-size=&quot;size16&quot;&gt;아래 코드를 작성하여 프로젝트에 포함한 뒤 GitHub에 Push합니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQxho&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;# 파이프라인 이름 지정
name: Push 기반 CI/CD 테스트

# 1. 트리거(Trigger) 정의
# main 브랜치에 push 이벤트가 발생하면 이 워크플로우가 자동으로 실행됩니다.
on:
  push:
    branches:
      - main

# 2. 수행할 작업(Jobs) 정의
jobs:
  ci:
    # GitHub에서 제공하는 최신 Ubuntu 가상 환경(Runner)에서 작업 실행
    runs-on: ubuntu-latest

    steps:
      # Step 1: GitHub 저장소에 등록된 최신 코드를 가상 환경으로 가져옴(Checkout)
      - name: 코드 checkout
        uses: actions/checkout@v4

      # Step 2: 코드 전달 상태 및 테스트 검증
      - name: 확인 검증
        # 여러 줄의 Bash 명령어를 실행할 때는 '|' 부호를 사용합니다.
        run: |
          pwd
          ls -al
          cat main.py
        shell: bash

      # Step 3: SCP(Secure Copy)를 이용해 AWS EC2 서버로 소스 코드 전송
      - name: source code copy to EC2
        uses: appleboy/scp-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.EC2_KEY }}
          port: 22
          # 복사할 대상 ('.' 은 현재 프로젝트의 모든 파일)
          source: .
          # EC2 서버 내부에서 파일이 복사되어 들어갈 경로
          target: &quot;/home/ubuntu/projects&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;35&quot; data-ke-size=&quot;size23&quot;&gt;  한 걸음 더! (실무 팁: 코드 전송 후 서비스 자동 재시작)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;36&quot; data-ke-size=&quot;size16&quot;&gt;현재 작성된 scp-action은 소스 코드를 서버로 '전송'하는 역할만 수행합니다. 실제 배포가 완료되려면 전송이 끝난 후 &lt;b data-index-in-node=&quot;70&quot; data-path-to-node=&quot;36&quot;&gt;FastAPI/Flask 백엔드 서버 프로세스를 재시작&lt;/b&gt;해 주어야 새 코드가 반영됩니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;37&quot; data-ke-size=&quot;size16&quot;&gt;이때는 appleboy/ssh-action을 파이프라인 마지막 스텝에 추가하여 EC2 명령어를 실행해 주는 것이 좋습니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQxxo&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;      # Step 4 (추가 권장): EC2 서버 접속 후 서비스 프로세스 재시작
      - name: SSH로 EC2 접속 후 애플리케이션 재시작
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.HOST }}
          username: ${{ secrets.USERNAME }}
          key: ${{ secrets.EC2_KEY }}
          port: 22
          script: |
            cd /home/ubuntu/projects
            # 예시: 기존 uvicorn/python 프로세스 종료 후 재구동 (또는 systemctl restart / docker-compose restart 등)
            sudo systemctl restart my_app.service
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h2 data-path-to-node=&quot;40&quot; data-ke-size=&quot;size26&quot;&gt;4. 마치며&lt;/h2&gt;
&lt;p data-path-to-node=&quot;41&quot; data-ke-size=&quot;size16&quot;&gt;GitHub Actions를 활용하면 복잡한 빌드 및 배포 과정을 손쉽게 자동화할 수 있습니다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;42&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;42,0,0&quot;&gt;main 브랜치에 코드 Push&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;42,1,0&quot;&gt;GitHub Actions가 이를 감지하여 최신 코드 검증&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;42,2,0&quot;&gt;AWS EC2 서버로 파일 전송 및 서비스 자동으로 재시작&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-path-to-node=&quot;43&quot; data-ke-size=&quot;size16&quot;&gt;이 파이프라인 구축을 통해 수동 배포로 인한 실수(Human Error)를 방지하고, 빠르고 안전하게 서비스를 업데이트할 수 있습니다. 실무 프로젝트에서도 차근차근 적용해 보세요!&lt;/p&gt;
&lt;p data-path-to-node=&quot;43&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;43&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;오늘의 한 마디&lt;/b&gt;&lt;/p&gt;
&lt;p data-path-to-node=&quot;43&quot; data-ke-size=&quot;size16&quot;&gt;업무 진행하면서 운영중인 서버에 파일을 직접 배포하고 재시작할 때면 얼마나 마음이 떨리는지 직접해보지 않으면 알지 못할겁니다. 이런 ci/cd 기술을 개발시 미리 만들어 놓고 진행하는 것이 백번 천번 좋습니다. 요즘은 ai의 발달로 ci/cd하는 것도 점점 쉬워지지 않을까 생각이 듭니다. 명령어만 잘 치면 말이죠.&lt;/p&gt;
&lt;p data-path-to-node=&quot;43&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;43&quot; data-ke-size=&quot;size16&quot;&gt;확실히 ci/cd가 있는 프로젝트와 없는 프로젝트는 차이가 너무 납니다. 어떤 미친 프로젝트는 형상관리도 안되고 있어 제가 직접 svn을 설치하여 프로젝트 형상관리를 그제서야 진행한 것도 있습니다... 하 갑자기 생각하니 열받으니 여기까지만 하시죠 ㅎㅎ&lt;/p&gt;</description>
      <category>코딩 개발/Git</category>
      <category>CD</category>
      <category>CI</category>
      <category>deploy.yml</category>
      <category>git</category>
      <category>github</category>
      <category>github actions</category>
      <author>호소세</author>
      <guid isPermaLink="true">https://pabeba.tistory.com/293</guid>
      <comments>https://pabeba.tistory.com/293#entry293comment</comments>
      <pubDate>Tue, 18 Aug 2026 18:39:51 +0900</pubDate>
    </item>
    <item>
      <title>[Git/GitHub] GitHub 원격 저장소 생성, 커밋&amp;middot;푸시 및 취소(Reset/Revert)</title>
      <link>https://pabeba.tistory.com/292</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;GitHub를 활용해 1인 프로젝트를 관리할 때 필수적으로 거치는&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원격 저장소 생성 ➔ 로컬 복사(Clone) ➔ 작업 ➔ 스테이징(Add) ➔ 커밋(Commit) ➔ 푸시(Push)의 전체 과정과,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업 도중 실수가 발생했을 때 유용한 &lt;b data-index-in-node=&quot;144&quot; data-path-to-node=&quot;4&quot;&gt;작업 취소 및 되돌리기(Restore/Reset/Revert)&lt;/b&gt; 방법을 알기 쉽게 정리해 보겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size26&quot;&gt;1. 원격 저장소(Remote Repository) 생성하기&lt;/h2&gt;
&lt;p data-path-to-node=&quot;7&quot; data-ke-size=&quot;size16&quot;&gt;가장 먼저 GitHub 웹사이트에서 프로젝트의 중심이 될 원격 저장소를 생성합니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size23&quot;&gt;  생성 절차 및 옵션&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;9&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;GitHub 우측 상단의 &lt;b data-index-in-node=&quot;14&quot; data-path-to-node=&quot;9,0,0&quot;&gt;+&lt;/b&gt; 버튼 클릭 ➔ &lt;b data-index-in-node=&quot;24&quot; data-path-to-node=&quot;9,0,0&quot;&gt;New repository&lt;/b&gt; 선택&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,1,0&quot;&gt;General 설정&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;9,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,1,1,0,0&quot;&gt;Repository name&lt;/b&gt;: my_project (프로젝트의 성격을 나타내는 직관적인 이름으로 지정)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,1,1,1,0&quot;&gt;Description&lt;/b&gt;: git 사용 연습 (저장소에 대한 간단한 설명 입력)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,2,0&quot;&gt;Configuration 설정&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;9,2,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,2,1,0,0&quot;&gt;Visibility&lt;/b&gt;: Public(공개) 또는 Private(비공개) 선택 (팀 작업이나 보안이 필요한 소스코드는 Private 권장)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,2,1,1,0&quot;&gt;Add a README file&lt;/b&gt;: ON (프로젝트 소개 문서를 기본 생성합니다. OFF로 생성 후 나중에 직접 만들어도 무방합니다.)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,2,1,2,0&quot;&gt;Add .gitignore&lt;/b&gt;: Python 검색 후 선택&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1895&quot; data-origin-height=&quot;274&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MzphH/dJMcahecI7W/0DWE1yrkHyIrthTMPCzBS1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MzphH/dJMcahecI7W/0DWE1yrkHyIrthTMPCzBS1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MzphH/dJMcahecI7W/0DWE1yrkHyIrthTMPCzBS1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMzphH%2FdJMcahecI7W%2F0DWE1yrkHyIrthTMPCzBS1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1895&quot; height=&quot;274&quot; data-origin-width=&quot;1895&quot; data-origin-height=&quot;274&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;691&quot; data-origin-height=&quot;479&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMXPHh/dJMb99NTpla/6EKs2hkCeTwtE73PWDFcOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMXPHh/dJMb99NTpla/6EKs2hkCeTwtE73PWDFcOk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMXPHh/dJMb99NTpla/6EKs2hkCeTwtE73PWDFcOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMXPHh%2FdJMb99NTpla%2F6EKs2hkCeTwtE73PWDFcOk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;691&quot; height=&quot;479&quot; data-origin-width=&quot;691&quot; data-origin-height=&quot;479&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;319&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7fErQ/dJMb99NTplw/bNEk3LKXD6E6vJAybAqgA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7fErQ/dJMb99NTplw/bNEk3LKXD6E6vJAybAqgA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7fErQ/dJMb99NTplw/bNEk3LKXD6E6vJAybAqgA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7fErQ%2FdJMb99NTplw%2FbNEk3LKXD6E6vJAybAqgA0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;697&quot; height=&quot;319&quot; data-origin-width=&quot;697&quot; data-origin-height=&quot;319&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;10&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;10,0&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b data-index-in-node=&quot;3&quot; data-path-to-node=&quot;10,0&quot;&gt;.gitignore 파일이란?&lt;/b&gt; Python 실행 시 생성되는 임시 파일, 가상환경 폴더(venv), 데이터베이스 비밀번호가 담긴 환경변수 파일(.env) 등 &lt;b data-index-in-node=&quot;91&quot; data-path-to-node=&quot;10,0&quot;&gt;Git이 추적할 필요가 없거나 외부에 유출되면 안 되는 파일들을 자동으로 제외&lt;/b&gt;해 주는 아주 중요한 설정 파일입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,0,0&quot;&gt;Add a license&lt;/b&gt;: 현재는 미선택 (추후 Open Source 라이선스가 필요한 경우 선택)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;12,0,0&quot;&gt;&amp;nbsp; &amp;nbsp; 4. Create repository&lt;/b&gt; 버튼 클릭으로 원격 저장소 생성 완료!&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;14&quot; data-ke-size=&quot;size26&quot;&gt;2. 원격 저장소 로컬 PC로 클론(Clone)하기&lt;/h2&gt;
&lt;p data-path-to-node=&quot;15&quot; data-ke-size=&quot;size16&quot;&gt;생성된 원격 저장소를 내 컴퓨터(로컬 PC)로 가져오는 작업입니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;16&quot; data-ke-size=&quot;size23&quot;&gt;  Clone 수행 과정&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;17&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;생성된 GitHub 저장소 메인 화면에서 초록색 &lt;b data-index-in-node=&quot;27&quot; data-path-to-node=&quot;17,0,0&quot;&gt;Code&lt;/b&gt; 버튼 클릭 ➔ &lt;b data-index-in-node=&quot;40&quot; data-path-to-node=&quot;17,0,0&quot;&gt;SSH&lt;/b&gt; 또는 &lt;b data-index-in-node=&quot;47&quot; data-path-to-node=&quot;17,0,0&quot;&gt;HTTPS&lt;/b&gt; 주소 복사&lt;/li&gt;
&lt;li&gt;로컬 PC의 터미널(CMD / PowerShell / Bash)에서 작업할 디렉토리로 이동:&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;422&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baWCqs/dJMcac4Ydr0/KyNr5KOrxoSPXn13mnMFZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baWCqs/dJMcac4Ydr0/KyNr5KOrxoSPXn13mnMFZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baWCqs/dJMcac4Ydr0/KyNr5KOrxoSPXn13mnMFZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaWCqs%2FdJMcac4Ydr0%2FKyNr5KOrxoSPXn13mnMFZk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;688&quot; height=&quot;422&quot; data-origin-width=&quot;688&quot; data-origin-height=&quot;422&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQ-Rk&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;taggerscript&quot;&gt;&lt;code&gt;C:\Users\Dell3571&amp;gt; cd Desktop/workspace
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;복사한 원격 저장소 주소를 이용해 클론 실행:&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQ-hk&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;git clone git@github.com:[유저아이디]/my_project.git&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQ-xk&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Cloning into 'my_project'...
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0 (from 0)
Receiving objects: 100% (4/4), done.
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클론이 완료되면 my_project 폴더가 생성됩니다. VS Code 등의 에디터로 해당 폴더를 열어 작업을 시작합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;381&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csmXiR/dJMcacqrFRS/qK1YoWWISFzlYdKvimMNqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csmXiR/dJMcacqrFRS/qK1YoWWISFzlYdKvimMNqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csmXiR/dJMcacqrFRS/qK1YoWWISFzlYdKvimMNqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsmXiR%2FdJMcacqrFRS%2FqK1YoWWISFzlYdKvimMNqk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;680&quot; height=&quot;381&quot; data-origin-width=&quot;680&quot; data-origin-height=&quot;381&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;24&quot; data-ke-size=&quot;size26&quot;&gt;3. 1인 개발 형상관리 워크플로우 (개발 ➔ 스테이징 ➔ 커밋 ➔ 푸시)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;25&quot; data-ke-size=&quot;size16&quot;&gt;Git으로 코드 이력을 관리할 때는 크게 3가지 영역(Working Directory ➔ Staging Area ➔ Repository)을 거치게 됩니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQ_Bk&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;[ Working Directory ] ──(git add)──&amp;gt; [ Staging Area ] ──(git commit)──&amp;gt; [ Local Repo ] ──(git push)──&amp;gt; [ Remote Repo ]
    (코드 작성/수정)                    (장바구니)                         (로컬 기록)                    (GitHub)
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;27&quot; data-ke-size=&quot;size23&quot;&gt;1) 기능 개발 (Working Directory)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;28&quot; data-ke-size=&quot;size16&quot;&gt;새로운 파일 app.py를 생성하고 코드를 작성합니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQ_Rk&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;print(&quot;hi&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;337&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xJXSg/dJMcaic9jnG/o9LtB97KZzxYDONB8M7WD1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xJXSg/dJMcaic9jnG/o9LtB97KZzxYDONB8M7WD1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xJXSg/dJMcaic9jnG/o9LtB97KZzxYDONB8M7WD1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxJXSg%2FdJMcaic9jnG%2Fo9LtB97KZzxYDONB8M7WD1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;623&quot; height=&quot;337&quot; data-origin-width=&quot;623&quot; data-origin-height=&quot;337&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;30&quot; data-ke-size=&quot;size23&quot;&gt;2) 스테이징 (Staging / git add)&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;763&quot; data-origin-height=&quot;349&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cFmbsL/dJMcacjzvjx/kfMbja7eQZbubhrWXosFGk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cFmbsL/dJMcacjzvjx/kfMbja7eQZbubhrWXosFGk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cFmbsL/dJMcacjzvjx/kfMbja7eQZbubhrWXosFGk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcFmbsL%2FdJMcacjzvjx%2FkfMbja7eQZbubhrWXosFGk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;763&quot; height=&quot;349&quot; data-origin-width=&quot;763&quot; data-origin-height=&quot;349&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;31&quot; data-ke-size=&quot;size16&quot;&gt;변경 사항을 커밋하기 전에 &quot;장바구니(Staging Area)&quot;에 담는 단계입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;변경사항 전체 올리기:&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;git add .
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;32&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;32,1,0&quot;&gt;특정 파일만 올리기&lt;/b&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;git add app.py
&lt;/code&gt;&lt;/pre&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;473&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDJeXh/dJMcacjzvkP/Tk1NKGdhVjbQVVU6gKJmsk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDJeXh/dJMcacjzvkP/Tk1NKGdhVjbQVVU6gKJmsk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDJeXh/dJMcacjzvkP/Tk1NKGdhVjbQVVU6gKJmsk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDJeXh%2FdJMcacjzvkP%2FTk1NKGdhVjbQVVU6gKJmsk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;768&quot; height=&quot;473&quot; data-origin-width=&quot;768&quot; data-origin-height=&quot;473&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h4 data-path-to-node=&quot;33&quot; data-ke-size=&quot;size20&quot;&gt;  [취소하기] 스테이징 되돌리기 (Unstage)&lt;/h4&gt;
&lt;p data-path-to-node=&quot;34&quot; data-ke-size=&quot;size16&quot;&gt;장바구니에 잘못 담은 파일을 다시 작업 영역으로 되돌립니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;35&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;35,0,0&quot;&gt;전체 파일 스테이징 취소&lt;/b&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;git restore --staged .
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;35&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;35,1,0&quot;&gt;특정 파일 스테이징 취소&lt;/b&gt;:&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;git restore --staged app.py
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;36&quot; data-ke-size=&quot;size23&quot;&gt;3) 커밋 (Commit / git commit)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;37&quot; data-ke-size=&quot;size16&quot;&gt;스테이징 영역에 올라온 파일들을 어떤 작업을 했는지 설명하는 메모와 함께 로컬 저장소(.git)에 영구적으로 기록합니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQgho&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;git commit -m &quot;Feat: 메인코드 작성&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-path-to-node=&quot;39&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;39,0&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b data-index-in-node=&quot;3&quot; data-path-to-node=&quot;39,0&quot;&gt;좋은 커밋 메시지 작성 태그 (Commit Convention)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;39,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Feat: 새로운 기능 추가&lt;/li&gt;
&lt;li&gt;Fix: 버그 수정&lt;/li&gt;
&lt;li&gt;Docs: 문서 수정 (README 등)&lt;/li&gt;
&lt;li&gt;Refactor: 코드 리팩토링 (기능 변경 없는 구조 개선)&lt;/li&gt;
&lt;li&gt;Chore: 빌드 업무, 패키지 매니저 설정 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;501&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pFWWq/dJMcahk0mge/PXhMZ1OKYzKVsLaXObKI70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pFWWq/dJMcahk0mge/PXhMZ1OKYzKVsLaXObKI70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pFWWq/dJMcahk0mge/PXhMZ1OKYzKVsLaXObKI70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpFWWq%2FdJMcahk0mge%2FPXhMZ1OKYzKVsLaXObKI70%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1260&quot; height=&quot;501&quot; data-origin-width=&quot;1260&quot; data-origin-height=&quot;501&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-path-to-node=&quot;40&quot; data-ke-size=&quot;size20&quot;&gt;  [취소하기] 로컬 커밋 되돌리기 (git reset)&lt;/h4&gt;
&lt;p data-path-to-node=&quot;41&quot; data-ke-size=&quot;size16&quot;&gt;이미 수행한 커밋을 취소하고 이전 상태로 되돌릴 수 있습니다. reset 명령어의 옵션 차이를 이해하는 것이 중요합니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;41&quot; data-ke-size=&quot;size16&quot;&gt;(이건 직접 해보시면 바로 느낌 옵니다.)&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;42&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;42,0,0&quot;&gt;--soft&lt;/b&gt;: 코드는 유지하고, &lt;b data-index-in-node=&quot;18&quot; data-path-to-node=&quot;42,0,0&quot;&gt;커밋만 취소&lt;/b&gt;하여 파일을 &lt;b data-index-in-node=&quot;31&quot; data-path-to-node=&quot;42,0,0&quot;&gt;스테이징(Staging) 상태&lt;/b&gt;로 되돌립니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;git reset --soft HEAD^
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;42&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;42,1,0&quot;&gt;--mixed (기본값)&lt;/b&gt;: 코드는 유지하고, &lt;b data-index-in-node=&quot;25&quot; data-path-to-node=&quot;42,1,0&quot;&gt;커밋과 스테이징을 모두 취소&lt;/b&gt;하여 &lt;b data-index-in-node=&quot;43&quot; data-path-to-node=&quot;42,1,0&quot;&gt;개발(Unstaged) 상태&lt;/b&gt;로 되돌립니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;sql&quot;&gt;&lt;code&gt;git reset HEAD^
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;42&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;42,2,0&quot;&gt;--hard&lt;/b&gt;: 커밋, 스테이징 취소는 물론 &lt;b data-index-in-node=&quot;24&quot; data-path-to-node=&quot;42,2,0&quot;&gt;작성했던 코드까지 완전히 파기&lt;/b&gt;하고 이전 커밋 시점으로 되돌립니다. &lt;i data-index-in-node=&quot;61&quot; data-path-to-node=&quot;42,2,0&quot;&gt;(※ 복구가 어려우므로 주의해서 사용해야 합니다.)&lt;/i&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;git reset --hard HEAD^
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;44&quot; data-ke-size=&quot;size23&quot;&gt;4) 푸시 (Push / git push)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;45&quot; data-ke-size=&quot;size16&quot;&gt;로컬 저장소에 기록된 커밋들을 GitHub 원격 저장소로 업로드(동기화)합니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQhho&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;maxima&quot;&gt;&lt;code&gt;git push origin main
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQhxo&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Writing objects: 100% (3/3), 341 bytes | 341.00 KiB/s, done.
To github.com:ucoccto/my_project.git
   5ab9259..f0f2055  main -&amp;gt; main
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;48&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;48&quot; data-ke-size=&quot;size16&quot;&gt;푸시 완료 후 GitHub 웹사이트를 새로고침하면 내가 작성한 파일과 커밋 메시지가 정상적으로 반영된 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;50&quot; data-ke-size=&quot;size26&quot;&gt;4. 이미 푸시한 작업 안전하게 취소하기 (git revert)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;51&quot; data-ke-size=&quot;size16&quot;&gt;원격 저장소(GitHub)에 이미 git push까지 완료된 커밋을 취소할 때, git reset으로 히스토리를 강제로 삭제하고 푸시하면 원격 저장소와의 이력이 꼬여 협업이나 추적에 문제가 생길 수 있습니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;52&quot; data-ke-size=&quot;size16&quot;&gt;이때는 &lt;b data-index-in-node=&quot;4&quot; data-path-to-node=&quot;52&quot;&gt;이전 커밋을 삭제하는 것이 아니라, 해당 커밋의 작업을 반대로 수행하는 '새로운 커밋'을 생성&lt;/b&gt;하는 revert를 사용하는 것이 안전합니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQiBo&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;nginx&quot;&gt;&lt;code&gt;# 가장 최근 푸시된 커밋의 반대 작업을 담은 커밋 생성
git revert HEAD
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;54&quot; data-ke-size=&quot;size16&quot;&gt;git revert를 실행하면 에디터가 열리면서 리버트 커밋 메시지를 작성하게 됩니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;54&quot; data-ke-size=&quot;size16&quot;&gt;저장 후 닫은 뒤, 다시 git push origin main을 해주면 안전하게 취소 이력이 반영됩니다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;56&quot; data-ke-size=&quot;size26&quot;&gt; ️ 요약 및 정리&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;57&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;57,0,0&quot;&gt;원격 저장소 생성&lt;/b&gt;: GitHub에서 .gitignore 설정과 함께 저장소 생성&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;57,1,0&quot;&gt;클론&lt;/b&gt;: git clone &amp;lt;주소&amp;gt; 명령으로 내 PC로 가져오기&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;57,2,0&quot;&gt;기본 루틴&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;57,2,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파일 작성/수정 ➔ git add . (스테이징) ➔ git commit -m &quot;메시지&quot; (로컬 기록) ➔ git push origin main (원격 업로드)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;57,3,0&quot;&gt;취소 명령어 정리&lt;/b&gt;:
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;57,3,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스테이징 취소: git restore --staged &amp;lt;파일명&amp;gt;&lt;/li&gt;
&lt;li&gt;로컬 커밋 취소: git reset (--soft / --mixed / --hard) HEAD^&lt;/li&gt;
&lt;li&gt;푸시된 커밋 취소: git revert HEAD ➔ git push&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-path-to-node=&quot;58&quot; data-ke-size=&quot;size16&quot;&gt;Git의 단계별 흐름과 되돌리기 명령어들의 차이점을 이해하면 실수하더라도 당황하지 않고 안전하게 프로젝트를 관리하실 수 있습니다!&lt;/p&gt;</description>
      <category>코딩 개발/Git</category>
      <category>Add</category>
      <category>Clone</category>
      <category>commit</category>
      <category>git</category>
      <category>github</category>
      <category>Push</category>
      <category>Reset</category>
      <category>Restore</category>
      <category>revert</category>
      <author>호소세</author>
      <guid isPermaLink="true">https://pabeba.tistory.com/292</guid>
      <comments>https://pabeba.tistory.com/292#entry292comment</comments>
      <pubDate>Mon, 17 Aug 2026 18:10:40 +0900</pubDate>
    </item>
    <item>
      <title>[Git/GitHub] 개발 필수 도구 Git 기초 개념부터 SSH 인증 및 초기 세팅</title>
      <link>https://pabeba.tistory.com/291</link>
      <description>&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;현대 소프트웨어 개발에서 결코 빠질 수 없는 필수 도구인 &lt;b data-index-in-node=&quot;43&quot; data-path-to-node=&quot;4&quot;&gt;Git&lt;/b&gt;과 &lt;b data-index-in-node=&quot;48&quot; data-path-to-node=&quot;4&quot;&gt;GitHub&lt;/b&gt;의 개요부터, 초보자분들이 가장 헷갈려하시는 &lt;b data-index-in-node=&quot;79&quot; data-path-to-node=&quot;4&quot;&gt;SSH 공개키 연동 및 초기 환경 설정 과정&lt;/b&gt;을 깔끔하게 정리해 드리겠습니다.&lt;/p&gt;
&lt;h2 data-path-to-node=&quot;6&quot; data-ke-size=&quot;size26&quot;&gt;1. 개요 (Git &amp;amp; GitHub란?)&lt;/h2&gt;
&lt;h3 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size23&quot;&gt;  Git과 GitHub의 차이점 (지식 더하기)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;8&quot; data-ke-size=&quot;size16&quot;&gt;많은 분들이 Git과 GitHub를 같은 것으로 오해하곤 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;9&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,0,0&quot;&gt;Git&lt;/b&gt;: 내 컴퓨터(로컬)에서 코드의 변경 이력을 기록하고 관리하는 &lt;b data-index-in-node=&quot;38&quot; data-path-to-node=&quot;9,0,0&quot;&gt;분산 버전 관리 시스템(DVCS)&lt;/b&gt; 소프트웨어입니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;9,1,0&quot;&gt;GitHub&lt;/b&gt;: Git으로 관리되는 프로젝트들을 클라우드(원격)에 저장하고 공유할 수 있게 해주는 &lt;b data-index-in-node=&quot;54&quot; data-path-to-node=&quot;9,1,0&quot;&gt;웹 기반 저장소 서비스&lt;/b&gt;입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;10&quot; data-ke-size=&quot;size23&quot;&gt;  주요 기능&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;11&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,0,0&quot;&gt;협업 관리&lt;/b&gt;: 1인 개인 프로젝트부터 수십, 수백 명 단위의 대규모 팀 프로젝트까지 효율적인 소스코드 통합 및 동시 작업 지원&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,1,0&quot;&gt;형상 관리 &amp;amp; 이력 관리&lt;/b&gt;: 코드의 변경 내역을 시간순으로 저장하여 언제든 과거 특정 시점으로 복구 가능&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,2,0&quot;&gt;코드 분석 &amp;amp; 리팩토링&lt;/b&gt;: 브랜치(Branch) 기능을 활용해 안전하게 신규 기능을 개발하고 리팩토링 테스트 가능&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,3,0&quot;&gt;디버깅 &amp;amp; 트러블슈팅&lt;/b&gt;: 이슈(Issue) 관리 기능을 통해 버그를 추적하고, git blame 등을 통해 문제가 발생한 코드의 작성자와 시점 파악&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;11,4,0&quot;&gt;문서화 &amp;amp; AI 생산성 증대&lt;/b&gt;: Wiki, README를 통한 프로젝트 문서화 및 GitHub Copilot과 같은 AI 보조 도구 활용&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-path-to-node=&quot;12&quot; data-ke-size=&quot;size23&quot;&gt;  개인 이력 관리 (포트폴리오)&lt;/h3&gt;
&lt;p data-path-to-node=&quot;13&quot; data-ke-size=&quot;size16&quot;&gt;과거에는 깃허브의 '잔디(Commit 이력)'가 개발자의 성실함을 증명하는 핵심 이력이었습니다. 최근 AI 시대에 들어서며 단순 커밋의 수보다는 &lt;b data-index-in-node=&quot;81&quot; data-path-to-node=&quot;13&quot;&gt;어떤 프로젝트에 참가했고, 문제 해결을 위해 어떤 고민을 거쳤는지 증명하는 기록 도구&lt;/b&gt;로서의 성격이 강화되었습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size26&quot;&gt;2. Git 설치 및 GitHub 회원가입&lt;/h2&gt;
&lt;h3 data-path-to-node=&quot;16&quot; data-ke-size=&quot;size23&quot;&gt;1) Git 설치 (Windows 기준)&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://git-scm.com/install/windows&quot; data-ved=&quot;0CAAQ_4QMahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQnxk&quot; data-hveid=&quot;0&quot;&gt;Git 공식 다운로드 페이지&lt;/a&gt;에 접속하여 설치 프로그램을 다운로드합니다.&lt;/li&gt;
&lt;li&gt;기본 옵션 그대로 설치를 진행해 주시면 큰 이슈 없이 완료됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,2,0&quot;&gt;설치 확인&lt;/b&gt;: CMD(명령 프롬프트) 또는 PowerShell을 열고 아래 명령어를 입력해 정상 작동 여부를 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1229&quot; data-origin-height=&quot;812&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/k6NIU/dJMcaa0opQM/DNAwU8btCJN1c1Ma7rdk8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/k6NIU/dJMcaa0opQM/DNAwU8btCJN1c1Ma7rdk8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/k6NIU/dJMcaa0opQM/DNAwU8btCJN1c1Ma7rdk8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fk6NIU%2FdJMcaa0opQM%2FDNAwU8btCJN1c1Ma7rdk8k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1229&quot; height=&quot;812&quot; data-origin-width=&quot;1229&quot; data-origin-height=&quot;812&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQoBk&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;git
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-path-to-node=&quot;19&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;19,0&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;19,0&quot;&gt;출력 예시:&lt;/b&gt; usage: git [-v | --version] [-h | --help] ... 문구가 출력되면 정상 설치된 것입니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-path-to-node=&quot;20&quot; data-ke-size=&quot;size23&quot;&gt;2) GitHub 가입&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;21&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com&quot; data-ved=&quot;0CAAQ_4QMahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQoRk&quot; data-hveid=&quot;0&quot;&gt;GitHub 공식 홈페이지&lt;/a&gt;에서 개별 가입을 진행합니다. (Google 계정을 활용하면 빠르게 가입하실 수 있습니다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;23&quot; data-ke-size=&quot;size26&quot;&gt;3. SSH 공개키(Public Key) 등록 (인증 자동화)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;GitHub에 코드를 올리거나(push) 가져올 때(pull) 매번 아이디와 비밀번호를 입력하는 것은 번거로울 뿐만 아니라 보안상 권장되지 않습니다. 로컬 PC와 GitHub 간에 SSH 키(Key)를 등록해 두면 비밀번호 없이 안전하고 편리하게 자동 인증을 처리할 수 있습니다.&lt;/p&gt;
&lt;blockquote data-path-to-node=&quot;25&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;25,0&quot; data-ke-size=&quot;size16&quot;&gt;  &lt;b data-index-in-node=&quot;3&quot; data-path-to-node=&quot;25,0&quot;&gt;SSH 키 작동 원리 (비대칭키 암호화)&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;25,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,1,0,0&quot;&gt;비밀키 (id_rsa)&lt;/b&gt;: 내 컴퓨터에만 안전하게 보관되는 키 (절대 외부에 유출되면 안 됨)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;25,1,1,0&quot;&gt;공개키 (id_rsa.pub)&lt;/b&gt;: GitHub와 같은 원격 서버에 등록하는 키&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h3 data-path-to-node=&quot;26&quot; data-ke-size=&quot;size23&quot;&gt;Step 1: SSH 키 발급받기&lt;/h3&gt;
&lt;p data-path-to-node=&quot;27&quot; data-ke-size=&quot;size16&quot;&gt;CMD 터미널을 열고 본인의 GitHub 가입 이메일 주소를 넣은 후 아래 명령어를 실행합니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQohk&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;ssh-keygen -t rsa -C &quot;본인이메일@gmail.com&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;29&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;명령어 실행 후 비밀번호 입력창 등이 나오는데, &lt;b data-index-in-node=&quot;27&quot; data-path-to-node=&quot;29,0,0&quot;&gt;엔터(Enter) 키를 3회 연속 입력&lt;/b&gt;하여 기본값으로 생성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQoxk&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;bash&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;# 실행 결과 예시
Your identification has been saved in C:\Users\사용자계정/.ssh/id_rsa
Your public key has been saved in C:\Users\사용자계정/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:B2jQfb/lq542+w1e2v48r2cceYAr3oyeE07zFE4 본인이메일@gmail.com&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;31&quot; data-ke-size=&quot;size23&quot;&gt;Step 2: 공개키 복사하기&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;32&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;탐색기를 열어 위에 저장된 C:\Users\사용자계정\.ssh\ 디렉토리로 이동합니다.&lt;/li&gt;
&lt;li&gt;id_rsa.pub (공개키) 파일을 VS Code나 메모장으로 열어줍니다.&lt;/li&gt;
&lt;li&gt;ssh-rsa AAAAB3NzaC1... 로 시작하는 전체 텍스트 내용을 복사합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-path-to-node=&quot;33&quot; data-ke-size=&quot;size23&quot;&gt;Step 3: GitHub에 공개키 등록하기&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-path-to-node=&quot;34&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;[GitHub] 접속 후 로그인&lt;/li&gt;
&lt;li&gt;우측 상단 프로필 아이콘 클릭 &amp;gt; &lt;b data-index-in-node=&quot;19&quot; data-path-to-node=&quot;34,1,0&quot;&gt;Settings&lt;/b&gt; 진입&lt;/li&gt;
&lt;li&gt;좌측 메뉴의 &lt;b data-index-in-node=&quot;7&quot; data-path-to-node=&quot;34,2,0&quot;&gt;SSH and GPG keys&lt;/b&gt; 클릭&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;34,3,0&quot;&gt;New SSH key&lt;/b&gt; 버튼 클릭&lt;/li&gt;
&lt;li&gt;Title에는 PC 이름(예: My Laptop)을 적고, Key 란에 복사했던 id_rsa.pub 파일의 내용을 붙여 넣은 뒤 &lt;b data-index-in-node=&quot;71&quot; data-path-to-node=&quot;34,4,0&quot;&gt;Add SSH key&lt;/b&gt; 클릭&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1902&quot; data-origin-height=&quot;863&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cBMkfo/dJMcaasB2Sm/gaPes2ry5qV2PLwuZunkHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cBMkfo/dJMcaasB2Sm/gaPes2ry5qV2PLwuZunkHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cBMkfo/dJMcaasB2Sm/gaPes2ry5qV2PLwuZunkHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcBMkfo%2FdJMcaasB2Sm%2FgaPes2ry5qV2PLwuZunkHk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1902&quot; height=&quot;863&quot; data-origin-width=&quot;1902&quot; data-origin-height=&quot;863&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;658&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FFYSm/dJMb991xiM5/xHWRVkMyHubOkh4Wi5R4lk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FFYSm/dJMb991xiM5/xHWRVkMyHubOkh4Wi5R4lk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FFYSm/dJMb991xiM5/xHWRVkMyHubOkh4Wi5R4lk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFFYSm%2FdJMb991xiM5%2FxHWRVkMyHubOkh4Wi5R4lk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1226&quot; height=&quot;658&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;658&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;36&quot; data-ke-size=&quot;size26&quot;&gt;4. 로컬 PC Git 글로벌 환경 설정 (Global Config)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;37&quot; data-ke-size=&quot;size16&quot;&gt;Git으로 코드 이력을 남길 때(Commit), &quot;누가 이 코드를 작성했는지&quot; 기록을 남겨야 합니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;37&quot; data-ke-size=&quot;size16&quot;&gt;이를 위해 터미널에서 글로벌 사용자 정보를 설정해줍니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;38&quot; data-ke-size=&quot;size23&quot;&gt;1) 사용자 이메일 및 이름 설정&lt;/h3&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQpBk&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# GitHub에 가입한 이메일 입력
git config --global user.email &quot;본인이메일@gmail.com&quot;

# GitHub 프로필 이름(닉네임) 입력
git config --global user.name &quot;본인닉네임&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-path-to-node=&quot;40&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;p data-path-to-node=&quot;40,0&quot; data-ke-size=&quot;size16&quot;&gt;⚠️ &lt;b data-index-in-node=&quot;3&quot; data-path-to-node=&quot;40,0&quot;&gt;주의&lt;/b&gt;: 설정하는 이메일은 반드시 GitHub 계정에 등록된 이메일과 동일해야 커밋 내역이 본인의 GitHub 프로필(잔디)에 올바르게 연동됩니다!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3 data-path-to-node=&quot;41&quot; data-ke-size=&quot;size23&quot;&gt;2) 설정 내용 확인&lt;/h3&gt;
&lt;p data-path-to-node=&quot;42&quot; data-ke-size=&quot;size16&quot;&gt;정상적으로 설정이 완료되었는지 아래 명령어로 목록을 확인합니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQpRk&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;git config --list
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi-rfDDh-WVAxUAAAAAHQAAAAAQphk&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;# 주요 설정 확인 목록 예시
init.defaultbranch=master (또는 main)
user.email=본인이메일@gmail.com
user.name=본인닉네임&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>코딩 개발/Git</category>
      <category>git</category>
      <category>github</category>
      <category>global config</category>
      <category>ssh키</category>
      <author>호소세</author>
      <guid isPermaLink="true">https://pabeba.tistory.com/291</guid>
      <comments>https://pabeba.tistory.com/291#entry291comment</comments>
      <pubDate>Fri, 14 Aug 2026 18:43:09 +0900</pubDate>
    </item>
    <item>
      <title>Docker Compose - FastAPI + MySQL 다중 컨테이너 환경 구축하기</title>
      <link>https://pabeba.tistory.com/290</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;559&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d9nLAe/dJMcadQhrea/vmUdNivakDZs8DRwkDJC71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d9nLAe/dJMcadQhrea/vmUdNivakDZs8DRwkDJC71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d9nLAe/dJMcadQhrea/vmUdNivakDZs8DRwkDJC71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd9nLAe%2FdJMcadQhrea%2FvmUdNivakDZs8DRwkDJC71%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1024&quot; height=&quot;559&quot; data-origin-width=&quot;1024&quot; data-origin-height=&quot;559&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-path-to-node=&quot;1&quot; data-ke-size=&quot;size16&quot;&gt;이전 포스팅에서 단일 컨테이너를 생성하는 Dockerfile에 대해 알아보았다면, 오늘은 여러 개의 컨테이너를 하나로 묶어서 일괄 관리할 수 있는 도구, '&lt;b&gt;Docker Compose&lt;/b&gt;(&lt;b&gt;도커 컴포즈&lt;/b&gt;)'에 대해 정리해 보겠습니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;1&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;2&quot; data-ke-size=&quot;size16&quot;&gt;실제 웹 서비스는 단일 프로그램으로 돌아가지 않습니다. 웹 서버, 백엔드 애플리케이션, 데이터베이스가 각각의 역할을 맡아 유기적으로 통신해야 하죠. 복잡해지는 컨테이너들을 명령어 하나로 제어하는 방법을 지금부터 알아보겠습니다.&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;4&quot; data-ke-size=&quot;size26&quot;&gt;1. Docker Compose 개요&lt;/h2&gt;
&lt;p data-path-to-node=&quot;5&quot; data-ke-size=&quot;size16&quot;&gt;Docker Compose는 &lt;b data-index-in-node=&quot;16&quot; data-path-to-node=&quot;5&quot;&gt;특정 서비스를 구성하는 모든 컨테이너 요소를 한 번에(일괄적으로) 정의하고 실행할 때 사용하는 도구&lt;/b&gt;입니다. 주로 docker-compose.yml (또는 compose.yaml) 파일에 설정을 명시하여 사용합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;6&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,0,0&quot;&gt;통상적인 웹 서비스 아키텍처&lt;/b&gt; 일반적으로 다음과 같은 3계층(3-Tier) 구조로 컨테이너를 분리하여 구성합니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;6,0,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,0,1,0,0&quot;&gt;Web Server&lt;/b&gt;: Nginx 컨테이너 (정적 자원 처리 및 리버스 프록시 역할)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,0,1,1,0&quot;&gt;WAS Server&lt;/b&gt;: FastAPI 컨테이너 (비즈니스 로직 처리, Python + Uvicorn + FastAPI)&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,0,1,2,0&quot;&gt;DB Server&lt;/b&gt;: MySQL 컨테이너 (데이터 저장)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0&quot;&gt;사용 범위 및 한계&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;6,1,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;도커 컴포즈는 &lt;b data-index-in-node=&quot;8&quot; data-path-to-node=&quot;6,1,1,0,0&quot;&gt;1개의 물리적인 호스트 PC(단일 OS)&lt;/b&gt; 내에서 여러 컨테이너를 묶어 실행하는 데 최적화되어 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;  지식 더하기: 만약 트래픽이 몰려 여러 대의 서버(노드)로 분산 처리를 하거나 오토 스케일링(확장)이 필요한 대규모 구조라면, 도커 컴포즈의 범위를 넘어서므로 쿠버네티스(Kubernetes)와 같은 컨테이너 오케스트레이션 도구로 넘어가야 합니다.&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;8&quot; data-ke-size=&quot;size26&quot;&gt;2. docker-compose.yml 파일 작성 및 분석&lt;/h2&gt;
&lt;p data-path-to-node=&quot;9&quot; data-ke-size=&quot;size16&quot;&gt;웹 서비스의 데이터베이스(MySQL)와 백엔드 애플리케이션(FastAPI)을 정의한 컴포즈 파일 예시입니다. YAML 형식은 들여쓰기(띄어쓰기 2칸)가 매우 중요하므로 작성 시 주의해야 합니다.&lt;/p&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi2_c3RzeKVAxUAAAAAHQAAAAAQpjg&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;# 각각의 서비스 주체들을 구성합니다. 각 주체는 하나의 독립된 컨테이너가 됩니다.
services:
  # 1. 데이터베이스 서비스
  # 서비스명(db)은 컨테이너명과 통상 일치시키며, 도커 네트워크 내부에서 도메인 주소로 사용됩니다.
  db:
    image: mysql
    container_name: mysql_db
    # restart 정책: 컨테이너가 중단되거나 오류 발생, 재부팅 시 항상 자동으로 재구동되게 설정합니다.
    restart: always
    environment:
      MYSQL_ROOT_PASSWORD: 1234
      MYSQL_DATABASE: memo  # 컨테이너 생성 시 최초로 구성될 빈 데이터베이스 이름
      MYSQL_USER: guest
      MYSQL_PASSWORD: 1234
    # 볼륨 설정: 컨테이너가 삭제되어도 데이터는 보존되도록 네임드 볼륨을 마운트합니다.
    volumes:
      - mysql-vol:/var/lib/mysql
    ports:
      - &quot;3306:3306&quot;
    networks:
      - my-net

  # 2. 백엔드 애플리케이션 서비스 (FastAPI)
  app:
    # build: 도커 허브의 이미지를 받는 대신, ./app 디렉토리 내부의 Dockerfile을 읽어 직접 이미지를 빌드합니다.
    build: ./app
    container_name: fastapi_app
    # restart 정책: 수동으로 정지(stop)하지 않는 한 재시작을 시도합니다.
    restart: unless-stopped
    # command: Dockerfile의 CMD를 덮어쓰며, Uvicorn 데몬을 백그라운드로 띄워 서버를 가동합니다.
    command: uvicorn main:app --host 0.0.0.0 --port 8000
    # ports: &quot;호스트 포트 : 컨테이너 포트&quot; 형식으로 외부 접근을 개방합니다.
    ports:
      - &quot;8000:8000&quot;
    # 바인드 마운트: 호스트 OS(개발 PC)의 ./app 경로와 컨테이너의 /app 경로를 실시간 동기화합니다.
    volumes:
      - ./app:/app
    networks:
      - my-net
    # 의존성 명시: db 컨테이너가 먼저 구동된 후 app 컨테이너가 실행되도록 순서를 보장합니다.
    depends_on:
      - db

# 사용할 도커 네트워크를 정의합니다.
networks:
  my-net:
    driver: bridge

# 사용할 네임드 볼륨을 선언합니다.
volumes:
  mysql-vol:
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;blockquote data-path-to-node=&quot;11&quot; data-ke-style=&quot;style2&quot;&gt;  지식 더하기 (depends_on): depends_on은 단순히 '실행 순서'만 보장할 뿐, 내부 서비스(MySQL 프로세스)가 온전히 준비되어 연결 가능한 상태인지까지 기다려주지는 않습니다. 실제 실무에서는 DB 부팅이 늦어져 App이 DB 연결에 실패하는 경우가 발생하므로, healthcheck 설정을 추가하여 DB 프로세스 자체가 정상인지 확인한 후 App을 띄우는 심화 방식을 사용하기도 합니다.&lt;/blockquote&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;13&quot; data-ke-size=&quot;size26&quot;&gt;3. 백엔드(WAS) 구성을 위한 하위 파일들&lt;/h2&gt;
&lt;p data-path-to-node=&quot;14&quot; data-ke-size=&quot;size16&quot;&gt;앞선 docker-compose.yml에서 app 서비스는 ./app 폴더의 Dockerfile을 빌드하도록 설정했습니다. 해당 폴더에 들어갈 파일 구성은 다음과 같습니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;15&quot; data-ke-size=&quot;size23&quot;&gt;1) Dockerfile&lt;/h3&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi2_c3RzeKVAxUAAAAAHQAAAAAQpzg&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;# 1. 베이스 이미지 지정 (경량화된 slim 버전 사용)
FROM python:3.14.0-slim

# 2. 컨테이너 내부의 기본 작업 디렉토리 지정
WORKDIR /app

# 3. 라이브러리 설치 목록 파일 복사
COPY requirements.txt .

# 4. 파이썬 라이브러리 설치
RUN pip install -r requirements.txt

# 5. 원본 소스 코드 복사
# 실무에서는 COPY . . 방식을 주로 사용하며, 불필요한 파일은 .dockerignore로 걸러냅니다.
COPY main.py . 

# 6. 서버 가동 명령어 (도커 컴포즈의 command 속성으로 이관하였으므로 생략 가능합니다.)
# CMD [&quot;uvicorn&quot;, &quot;main:app&quot;, &quot;--reload&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;17&quot; data-ke-size=&quot;size23&quot;&gt;2) requirements.txt&lt;/h3&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi2_c3RzeKVAxUAAAAAHQAAAAAQqDg&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;fastapi
uvicorn
jinja2
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3 data-path-to-node=&quot;19&quot; data-ke-size=&quot;size23&quot;&gt;3) main.py (FastAPI 앱 코드)&lt;/h3&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi2_c3RzeKVAxUAAAAAHQAAAAAQqTg&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;ruby&quot;&gt;&lt;code&gt;# 1. 모듈 가져오기
from fastapi import FastAPI

# 2. FastAPI 객체 생성
app = FastAPI()

# 3. 라우터 설정: 특정 URL 요청에 대해 처리할 함수 매핑
@app.get(&quot;/&quot;)       # &quot;/&quot; 루트 경로 접근 시
def read_root():    # 응답으로 JSON 반환
    return {&quot;message&quot;: &quot;Hello World2&quot;}

@app.get(&quot;/items/{item_id}&quot;)
def read_item(item_id: int, q: str = None):
    return {&quot;item_id&quot;: item_id, &quot;q&quot;: q}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;22&quot; data-ke-size=&quot;size26&quot;&gt;4. 생성, 실행, 종료 (라이프사이클 관리)&lt;/h2&gt;
&lt;p data-path-to-node=&quot;23&quot; data-ke-size=&quot;size16&quot;&gt;도커 컴포즈가 작성된 폴더에서 터미널을 열고 명령어 단 한 줄만 입력하면, 정의된 모든 네트워크, 볼륨, 컨테이너가 순서에 맞게 한 번에 생성되고 구동됩니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;24&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;24&quot;&gt;1. 일괄 실행 (up)&lt;/b&gt;&lt;/h3&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi2_c3RzeKVAxUAAAAAHQAAAAAQqjg&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;26&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;-d 옵션을 주면 데몬(백그라운드) 모드로 실행되어 터미널을 계속 사용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;실행 시 Network, Volume이 먼저 생성되고, 의존성에 따라 mysql_db가 켜진 뒤 fastapi_app이 실행됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1515&quot; data-origin-height=&quot;212&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMsbUO/dJMcabkLgiZ/NSlPX1ylxON1tcyNKuwV5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMsbUO/dJMcabkLgiZ/NSlPX1ylxON1tcyNKuwV5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMsbUO/dJMcabkLgiZ/NSlPX1ylxON1tcyNKuwV5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMsbUO%2FdJMcabkLgiZ%2FNSlPX1ylxON1tcyNKuwV5K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1515&quot; height=&quot;212&quot; data-origin-width=&quot;1515&quot; data-origin-height=&quot;212&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;185&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tQBUN/dJMcadW7eF5/K0ZVBwwsGvzhFbwvc9IJ60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tQBUN/dJMcadW7eF5/K0ZVBwwsGvzhFbwvc9IJ60/img.png&quot; data-alt=&quot;정상 작동&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tQBUN/dJMcadW7eF5/K0ZVBwwsGvzhFbwvc9IJ60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtQBUN%2FdJMcadW7eF5%2FK0ZVBwwsGvzhFbwvc9IJ60%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;446&quot; height=&quot;185&quot; data-origin-width=&quot;446&quot; data-origin-height=&quot;185&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;정상 작동&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;27&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;27&quot;&gt;2. 일괄 종료 및 삭제 (down)&lt;/b&gt;&lt;/h3&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi2_c3RzeKVAxUAAAAAHQAAAAAQqzg&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;docker-compose down
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;29&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구동 중인 컨테이너들을 안전하게 정지한 뒤 삭제하고, 생성했던 네트워크 망(my-net)도 함께 삭제합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;29,1,0&quot;&gt;중요 포인트&lt;/b&gt;: down 명령어를 수행하여 컨테이너와 네트워크가 삭제되더라도, &lt;b data-index-in-node=&quot;43&quot; data-path-to-node=&quot;29,1,0&quot;&gt;데이터베이스가 저장된 볼륨(mysql-vol)은 절대 삭제되지 않고 유지&lt;/b&gt;됩니다!&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;30&quot; data-ke-size=&quot;size23&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;30&quot;&gt;3. 데이터 보존 확인&lt;/b&gt;&lt;/h3&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi2_c3RzeKVAxUAAAAAHQAAAAAQrDg&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;ebnf&quot;&gt;&lt;code&gt;docker-compose up -d
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;32&quot; data-ke-size=&quot;size16&quot;&gt;다시 서비스를 구동해 보면, 네트워크와 컨테이너는 새로 만들어지지만 볼륨은 기존 것을 그대로 마운트하기 때문에 DB에 저장해 둔 데이터가 안전하게 복구된 것을 확인할 수 있습니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;32&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;32&quot; data-ke-size=&quot;size23&quot;&gt;명령어 관련 추가 내용&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;1,0,0&quot;&gt;docker-compose up -d 단독 실행 시&lt;/b&gt; app 서비스의 빌드된 이미지가 로컬에 없는 최초 실행 상태라면, 도커 컴포즈가 자동으로 build: ./app 경로를 참조하여 이미지를 빌드한 후 컨테이너를 구동합니다. 만약 이미 빌드된 이미지가 존재한다면, Dockerfile의 변경 사항을 무시하고 기존 이미지를 재사용하여 구동합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;1,1,0&quot;&gt;docker-compose up -d --build 실행 시&lt;/b&gt; 기존 이미지의 존재 여부와 무관하게 Dockerfile을 바탕으로 이미지를 강제로 다시 빌드한 후 컨테이너를 갱신하여 구동합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-path-to-node=&quot;2&quot; data-ke-size=&quot;size16&quot;&gt;최초 실행이거나 컨테이너의 근본적인 환경(Dockerfile 내용 변경, 새로운 패키지 설치 등)에 변화가 없다면 --build 옵션 없이 실행해도 정상 구동됩니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;2&quot; data-ke-size=&quot;size16&quot;&gt;환경 설정이나 종속성 변경 사항을 이미지에 새로 반영해야 할 때만 --build 옵션을 추가하여 실행하면 됩니다.&lt;/p&gt;</description>
      <category>코딩 개발/Docker</category>
      <category>docker</category>
      <category>docker-compose</category>
      <category>yml</category>
      <author>호소세</author>
      <guid isPermaLink="true">https://pabeba.tistory.com/290</guid>
      <comments>https://pabeba.tistory.com/290#entry290comment</comments>
      <pubDate>Thu, 13 Aug 2026 18:34:35 +0900</pubDate>
    </item>
    <item>
      <title>Docker - Dockerfile (LABEL, ARG)</title>
      <link>https://pabeba.tistory.com/289</link>
      <description>&lt;h2 data-path-to-node=&quot;16&quot; data-ke-size=&quot;size26&quot;&gt;1. LABEL 및 ARG의 개념&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;17&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,0,0&quot;&gt;LABEL&lt;/b&gt;: 도커 이미지 자체에 부여하는 Key-Value 형태의 메타데이터입니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;17,1,0&quot;&gt;ARG&lt;/b&gt;: docker build가 실행되는 빌드 시점에만 유효한 변수입니다. 빌드가 완료된 후 구동되는 컨테이너 런타임 환경에서는 이 변수값에 접근할 수 없습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-hveid=&quot;9&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;FROM ubuntu

# ARG: 빌드 시점에만 존재하는 변수와 기본값 생성
ARG cus_title=&quot;도커 파일 기반 커스텀 이미지&quot;

# LABEL: 이미지 메타데이터에 변수값 적용
LABEL title=$cus_title
LABEL author=&quot;익명&quot;

# RUN: 빌드 로그에서 변수값 출력
RUN echo ${cus_title}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;19&quot; data-ke-size=&quot;size26&quot;&gt;2. 이미지 정보 조회 명령어 정정&lt;/h2&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;LABEL 정보는 컨테이너가 아닌 &lt;b data-index-in-node=&quot;19&quot; data-path-to-node=&quot;21&quot;&gt;이미지&lt;/b&gt;에 기록되는 메타데이터입니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;21&quot; data-ke-size=&quot;size16&quot;&gt;컨테이너가 해당 이미지를 기반으로 실행되면서 정보를 상속받기 때문에 컨테이너 inspect 명령에서도 확인할 수는 있으나, 순수하게 '이미지의 정보'를 확인하기 위한 정확한 명령어는 docker container inspect가 아닌 docker image inspect를 사용해야 합니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;22&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;22&quot;&gt;[이미지 정보 확인 명령어 적용]&lt;/b&gt;&lt;/p&gt;
&lt;div data-hveid=&quot;12&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;# 이미지 빌드
docker build -t test_ubuntu:1.5 ./step5

# 이미지를 기반으로 컨테이너 가동
docker run -itd --name test_ubuntu_1.5 test_ubuntu:1.5

# 이미지 메타데이터 상세 정보 확인 (정정된 명령어)
docker image inspect test_ubuntu:1.5
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;24&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;24&quot;&gt;[실행 결과 확인 (JSON 반환값 일부)]&lt;/b&gt;&lt;/p&gt;
&lt;div data-hveid=&quot;15&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;1c&quot;&gt;&lt;code&gt;&quot;Labels&quot;: {
    &quot;author&quot;: &quot;익명&quot;,
    &quot;title&quot;: &quot;도커 파일 기반 커스텀 이미지&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</description>
      <category>코딩 개발/Docker</category>
      <category>ARG</category>
      <category>docker</category>
      <category>Dockerfile</category>
      <category>Label</category>
      <author>호소세</author>
      <guid isPermaLink="true">https://pabeba.tistory.com/289</guid>
      <comments>https://pabeba.tistory.com/289#entry289comment</comments>
      <pubDate>Wed, 12 Aug 2026 18:01:37 +0900</pubDate>
    </item>
    <item>
      <title>Docker - Dockerfile (ENTRYPOINT, WORKDIR, ENV)</title>
      <link>https://pabeba.tistory.com/288</link>
      <description>&lt;p data-path-to-node=&quot;1&quot; data-ke-size=&quot;size16&quot;&gt;Dockerfile을 통해 컨테이너의 실행 명령을 지정하고, 내부 작업 디렉토리 및 환경 변수를 설정하는 방법입니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;1&quot; data-ke-size=&quot;size16&quot;&gt;원문에 기재된 실행 명령 관련 전제 중 일부 부정확한 부분을 정정 및 보완했습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;3&quot; data-ke-size=&quot;size26&quot;&gt;1. ENTRYPOINT와 CMD의 차이 및 결합 동작&lt;/h2&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;ENTRYPOINT [&quot;nginx&quot;]와 CMD [&quot;-g&quot;,&quot;daemon off;&quot;]의 결합이 CMD [&quot;nginx&quot;,&quot;-g&quot;,&quot;daemon off;&quot;]와 같다고 할 수 없습니다.&lt;/p&gt;
&lt;p data-path-to-node=&quot;4&quot; data-ke-size=&quot;size16&quot;&gt;이 둘은 런타임 시 인자값(Argument) 덮어쓰기(Override) 여부에 있어 명확한 차이가 존재하므로 분리하여 이해해야 합니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;5&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,0,0&quot;&gt;CMD&lt;/b&gt;: 컨테이너 실행 시 작동할 기본 명령을 지정합니다. 사용자가 docker run &amp;lt;이미지명&amp;gt; &amp;lt;추가명령어&amp;gt; 형태로 실행할 경우, Dockerfile 내부의 CMD 내용은 무시되고 사용자가 입력한 추가 명령어로 대체됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,1,0&quot;&gt;ENTRYPOINT&lt;/b&gt;: 컨테이너가 메인 프로세스로 실행할 고정된 실행 파일을 지정합니다. docker run 시 추가 인자를 입력하더라도 ENTRYPOINT의 실행 파일은 덮어쓰기 되지 않고 그대로 유지됩니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;5,2,0&quot;&gt;결합 사용&lt;/b&gt;: 두 명령어를 함께 작성할 경우, CMD는 ENTRYPOINT로 지정된 실행 파일에 전달할 '기본 매개변수' 역할을 수행합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi2_c3RzeKVAxUAAAAAHQAAAAAQvh0&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;dockerfile&quot;&gt;&lt;code&gt;FROM ubuntu

# ENTRYPOINT: 런타임 시 변경되지 않는 메인 실행 파일 지정
ENTRYPOINT [ &quot;nginx&quot; ]

# CMD: ENTRYPOINT에 전달할 기본 매개변수 (사용자가 docker run 시 다른 옵션으로 덮어쓰기 가능)
CMD [&quot;-g&quot;, &quot;daemon off;&quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;7&quot; data-ke-size=&quot;size26&quot;&gt;2. WORKDIR (작업 디렉토리)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;8&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;WORKDIR은 컨테이너 내부의 작업 위치를 변경합니다. 리눅스의 cd 명령어와 목적이 같습니다.&lt;/li&gt;
&lt;li&gt;한 번 지정되면 이후에 등장하는 ADD, COPY, RUN, CMD, ENTRYPOINT 명령어는 모두 해당 경로를 기준으로 동작합니다. 만약 명시한 디렉토리가 존재하지 않으면 도커 엔진이 해당 경로를 자동 생성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-path-to-node=&quot;9&quot; data-ke-size=&quot;size26&quot;&gt;3. ENV (환경 변수)&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;10&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;ENV는 컨테이너 내부 운영체제 환경에서 전역적으로 사용할 변수를 선언합니다.&lt;/li&gt;
&lt;li&gt;주로 데이터베이스 접속 정보, 타임존, 서비스 포트 등 애플리케이션에 필요한 동적 구성 값을 컨테이너에 전달할 때 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;div data-ved=&quot;0CAAQhtANahgKEwi2_c3RzeKVAxUAAAAAHQAAAAAQvx0&quot; data-hveid=&quot;0&quot;&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;# 권장 표기법: 한 줄에 여러 개의 환경 변수 선언 시 '=' 기호 사용
ENV MYSQL_USER=admin MYSQL_PORT=3306&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot; data-path-to-node=&quot;3&quot;&gt;ENTRYPOINT와 CMD의 차이&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 ENTRYPOINT와 CMD 의 차이에 대해 조금 더 궁금해서 더 찾아보았습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-path-to-node=&quot;0&quot; data-ke-size=&quot;size16&quot;&gt;두 방식의 핵심적인 차이는 &lt;b data-index-in-node=&quot;15&quot; data-path-to-node=&quot;0&quot;&gt;컨테이너 실행 시(docker run) 사용자가 입력하는 추가 인자(Argument)가 명령어를 덮어쓰는(Override) 방식&lt;/b&gt;에 있습니다.&lt;/p&gt;
&lt;h3 data-path-to-node=&quot;1&quot; data-ke-size=&quot;size23&quot;&gt;1. CMD [&quot;nginx&quot;, &quot;-g&quot;, &quot;daemon off;&quot;] 단독 사용&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;2&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,0,0&quot;&gt;기본 동작:&lt;/b&gt; 컨테이너 실행 시 nginx를 실행하며, -g daemon off;를 인자로 전달합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,1,0&quot;&gt;명령어 덮어쓰기:&lt;/b&gt; docker run 명령어 뒤에 새로운 명령어를 입력하면, CMD에 정의된 &lt;b data-index-in-node=&quot;52&quot; data-path-to-node=&quot;2,1,0&quot;&gt;전체 내용이 덮어씌워집니다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;2,2,0&quot;&gt;실행 예시:&lt;/b&gt; docker run &amp;lt;이미지명&amp;gt; bash
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;2,2,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;결과: nginx 대신 bash 프로세스가 실행됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;3&quot; data-ke-size=&quot;size23&quot;&gt;2. ENTRYPOINT [&quot;nginx&quot;] + CMD [&quot;-g&quot;, &quot;daemon off;&quot;] 혼합 사용&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;4&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,0,0&quot;&gt;기본 동작:&lt;/b&gt; ENTRYPOINT에 지정된 nginx를 항상 실행할 고정 실행 파일로 설정하고, CMD에 지정된 -g daemon off;를 기본 인자로 전달합니다. 아무 인자 없이 실행하면 1번 방식과 동일하게 작동합니다.&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,1,0&quot;&gt;명령어 덮어쓰기:&lt;/b&gt; docker run 명령어 뒤에 새로운 인자를 입력하면, ENTRYPOINT는 그대로 유지되고 &lt;b data-index-in-node=&quot;63&quot; data-path-to-node=&quot;4,1,0&quot;&gt;CMD에 지정된 인자 부분만 덮어씌워집니다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,2,0&quot;&gt;실행 예시:&lt;/b&gt; docker run &amp;lt;이미지명&amp;gt; -t
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;4,2,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;결과: CMD 부분이 대체되어 nginx -t가 실행됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;4,3,0&quot;&gt;실행 예시 2:&lt;/b&gt; docker run &amp;lt;이미지명&amp;gt; bash
&lt;ul style=&quot;list-style-type: disc;&quot; data-path-to-node=&quot;4,3,1&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;결과: nginx bash가 실행됩니다. (bash가 CMD를 덮어씀. 이는 nginx의 정상적인 실행 인자가 아니므로 오류가 발생합니다.)&lt;/li&gt;
&lt;li&gt;이 방식에서 nginx가 아닌 bash를 실행하려면 docker run --entrypoint bash &amp;lt;이미지명&amp;gt;과 같이 --entrypoint 옵션을 명시적으로 변경해야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-path-to-node=&quot;5&quot; data-ke-size=&quot;size23&quot;&gt;요약&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-path-to-node=&quot;6&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;실행 파일 고정 여부&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;docker run &amp;lt;이미지&amp;gt; [인자] 실행 시 덮어쓰기 대상&lt;/b&gt;&lt;/td&gt;
&lt;td&gt;&lt;b&gt;주 사용 목적&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,1,0,0&quot;&gt;CMD 단독&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,1,0&quot;&gt;고정 안 됨&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,2,0&quot;&gt;실행 파일을 포함한 명령어 전체&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,1,3,0&quot;&gt;실행 명령어를 유연하게 완전히 바꾸고 싶을 때&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,0,0&quot;&gt;&lt;b data-index-in-node=&quot;0&quot; data-path-to-node=&quot;6,2,0,0&quot;&gt;ENTRYPOINT + CMD&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,1,0&quot;&gt;고정됨 (nginx)&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,2,0&quot;&gt;CMD로 지정된 인자 부분만&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;span data-path-to-node=&quot;6,2,3,0&quot;&gt;메인 애플리케이션을 고정하고 전달할 옵션만 변경하고 싶을 때&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>코딩 개발/Docker</category>
      <category>cmd</category>
      <category>docker</category>
      <category>Dockerfile</category>
      <category>entrypoint</category>
      <category>enV</category>
      <category>WorkDir</category>
      <author>호소세</author>
      <guid isPermaLink="true">https://pabeba.tistory.com/288</guid>
      <comments>https://pabeba.tistory.com/288#entry288comment</comments>
      <pubDate>Tue, 11 Aug 2026 18:57:05 +0900</pubDate>
    </item>
  </channel>
</rss>