어느 정도 규모의 시스템을 구축하다 보면 다양한 배치작업이 필요한 일이 생기게 된다.

가령 특정 기간동안 유저의 거래 통계를 빠르게 조회하기 위해서 data warehouse 에 저장하거나 혹은 유저에게 주기적으로 특정 이메일을 보내는 등 특정 기간에 걸쳐 어떠한 행위를 반복적으로 처리해야 할 일이 생긴다. 이러한 배치작업을 처리하기 위해서 과거에는 unix cron job 등을 통해 이러한 배치작업을 처리했다.

하지만 이러한 cron 작업의 경우 단일 server 에서 하나의 프로세스로 돌아가는 만큼 그 안정성과 소스의 관리라는 측면에서 불안한 것이 사실이었고, 사실 해당 server 의 네트워크 상태가 불안정하거나 혹은 프로세스 또는 운영체제가 종료되는 경우 배치작업에 지장이 생기게 된다.

AWS 에서는 cloudwatch 와 lambda 를 통해 이러한 다양한 배치작업을 처리할 수 있는 기능을 제공하고, 이번 포스트에서는 이처럼 AWS 라는 클라우드 환경에서의 배치작업 처리를 다루어 보고자 한다.

What is AWS cloudwatch?

AWS cloudwatch 란 AWS 의 cloud resource 및 어플리케이션에 대한 monitoring service 이다.

간단하게 설명하면, AWS 에서 여러 자원을 사용하고 또 어플리케이션을 동작하면 AWS 는 이를 모두 클라우드 환경에서 실행하기 때문에 실제 bare metal 을 사용할때처럼 내가 사용하고자 하는 컴퓨팅 자원의 상태 및 로그등을 정확히 알기가 힘들다. 이를 해결하기 위해 AWS 는 각종 cloud resource 를 사용자가 쉽게 관리할 수 있도록 시각화시켜 내 클라우드 자원들이 잘 동작하고 있는지 알 수 있도록 별도의 서비스를 제공하고 이것이 바로 Cloudwatch 이다.

Cloudwatch 서비스를 이용하여 AWS 상에서 구동되고 있는 다양한 컴퓨팅 자원들의 상태를 리포팅 받고 또 시스템 로그들을 매우 간편하게 확인할 수 있다. 뿐만 아니라 여러 컴퓨팅 자원들을 지켜보며 특정 상황이나 시점에서 어떤 event 를 발생시킬 수도 있다.

종합하면, AWS 자원들을 모니터링 하는 cloudwatch 에서 내 자원들을 모니터링 할 수 있고, event 라는 개념을 통해 특정 시간 혹은 조건에 따라 어떤 event 를 만들고 이 event 가 어떤 행위를 일으킬 수 있다. 이러한 행위의 종류는 다양한데 이번 포스트에서는 특정 람다를 실행시키는 행위를 발생시켜 이를 통해 일련의 배치작업을 처리해 보고자 한다.

간략한 동작 순서

이번 포스트에서 배치작업은 다음의 순서에 따라 이루어 진다.

  1. AWS Cloudwatch 에 특정 시간마다 특정 람다를 호출하도록 하는 event 를 등록한다.
  2. Cloudwatch 는 위에서 설정한 내용에 따라 주기적으로 event 를 발생시키고 즉, 람다를 호출한다.
  3. 사용자가 특정 시간마다 호출된 람다 함수를 작성한다.
  4. 특정 시간 조건이 충족되면 람다함수가 호출된다.

이처럼 아주 간단한 절차에 따라 배치함수가 동작되고, 배치함수의 성공 유무 등 잘 동작하고 있는지 cloudwatch 에서 확인이 가능하다.

Getting started

자 이제 실제로 구현을 해보도록 하자!!

이와 같은 일련의 과정을 AWS console 을 통해 하는 것은 너무도 성가시고 실수에 취약하므로 본 포스트에서는 terraform 이라는 Infrastructure as Code 툴을 사용하며 terraform 을 모른더라도 pseudo code 라는 생각으로 보아도 쉽게 이해할 수 있으니 실제 terraform 이 궁금한 독자분이 계시다면 구글링을 통해 살펴보기 바란다…ㅎㅎ

제일 먼저 아래와 같이 매 시간마다 호출될 람다 함수를 만들어 보자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
resource "aws_lambda_function" "TestFunction" {
filename = "${path.module}/zips/TestFunction.zip"
source_code_hash = "${filebase64sha256("${path.module}/zips/TestFunction.zip")}"
function_name = "TestFunction"
role = "${aws_iam_role.iam_role_for_lambda.arn}"
handler = "index.lambda_handler"
runtime = "python3.6"
memory_size = "512"

vpc_config {
subnet_ids = ["${var.private_subnet_az1_id}"]
security_group_ids = ["${aws_security_group.lambda_sg.id}"]
}

timeout = "100"
}

코드를 할번 살펴보면 람다함수를 작성하고 이를 zip 파일로 압축하여 terraform 을 통해 zip 파일을 업로드하고 람다함수를 배포하는 것을 알 수 있다. Source_code_hash 는 현재 zip 파일의 hash를 통해 업데이트 되었다면 업데이트된 파일을 aws 로 업로드 하기 위함이며, role 에서 이 람다함수가 어떤 AWS 리소스들에 접근할 수 있을지에 대한 role을 넣어준다.

vpc_config 의 경우 어떤 vpc와 security group 에 속하는지 등을 표기한다.

다음으로는 아래와 같이 cloudwatch 에서 특정 시간마다 일으킬 이벤트 규칙을 정의한다.

1
2
3
4
5
6

resource "aws_cloudwatch_event_rule" "every_10pm" {
name = "every-10-pm"
description = "Fires every 10 pm"
schedule_expression = "cron(0 13 * * ? *)"
}

이벤트 규칙은 cron expression 으로 표현되니 자세한 문법은 cron expression 을 참조하길 바란다.

다음으로는 아래처럼 위 이벤트 규칙의 대상을 설정해 준다.

1
2
3
4
5
6

resource "aws_cloudwatch_event_target" "search_naver_every_10pm" {
rule = "${aws_cloudwatch_event_rule.every_10pm.name}"
target_id = "TestFunction"
arn = "${aws_lambda_function.TestFunction.arn}"
}

코드를 살펴보면 특정 이벤트 규칙이 어떤 람다 함수를 호출할지 해당 람다 함수의 ARN 을 통해 가르쳐 주고 있다.

마지막으로는 Cloudwatch 에게 람다함수를 호출 할 수 있는 권한을 주는 것이다.

1
2
3
4
5
6
7
resource "aws_lambda_permission" "allow_cloudwatch_to_call_search_naver" {
statement_id = "AllowExecutionFromCloudWatch"
action = "lambda:InvokeFunction"
function_name = "${aws_lambda_function.TestFunction.function_name}"
principal = "events.amazonaws.com"
source_arn = "${aws_cloudwatch_event_rule.every_10pm.arn}"
}

이것이 무슨말인지 잘 이해가 되지 않을 수 있다. cloudwatch 가 lambda 를 호출할 권한이라니? Cloudwatch 가 무슨 사람이라도 된단 말인가!?

AWS 에서는 여러 AWS 서비스가 다른 서비스의 어떤 작업을 수행하기 위한 자격을 부여할 수 있고 이러한 자격을 IAM Role 이라고 한다.

코드를 한번 살펴보면 위에서 principal 이란 어떤 AWS 서비스에게 권한을 부여할 것인지를 나타내고 여기서는 events.amazonaws.com (이는 아마존에서 정해둔 AWS 서비스에 대한 도메인이다.) 즉, cloudwatch 에서 발생하는 특정 event 에게 어떤 권한을 부여하겠다는 것이다. 또 action 에서는 “lambda:InvokeFunction” 즉 cloudwatch 이벤트로 하여금 어떤 람다함수를 호출할수 있는 권한을 부여한다 정도로 이해하면 되겠다. arn 은 물론 어떤 람다함수인지를 알려주는 것으로, 해당 람다 함수의 고유 id라고 이해하면 된다.

마지막으로 해야할 것은 위의 람다함수가 실행되면서 발생한 로그를 저장할 log group 을 설정해 주는 것이데 이는 아래와 같이 설정한다.

1
2
3
4
5

resource "aws_cloudwatch_log_group" "example" {
name = "/aws/lambda/TestFunction"
retention_in_days = 14
}

여기서 name 은 내 멋대로 하면 되나 싶지만 그렇지 않다.

위처럼 /aws/lambda/함수명 이라는 이름으로 정확히 log group 을 만들어주어야 아마존 람다가 해당 log group 에 로그를 쌓게 되니 주의하기 바란다.

OAuth2.0 은 무엇이며 왜 사용하는가?

OAuth 2.0 이란 써드 파티 어플리케이션의 인증을 위한 규약이다.

가령 내가 만든 어플리케이션이 구글의 서비스를 쓰기 위한 다양한 방법이 존재하는데, 대부분의 경우 내가 구글에 가서 인증키를 발급받은 다음에 이 인증키를 어플리케이션 내에 하드코드로 박아 넣는 방식을 사용해 왔다. 이러한 형태의 인증은 매우 흔한데 매우 많은 API 사업자들이 이러한 방식의 인증을 제공한다.

이 경우 해당 키가 탈취되면 매우 심각한 문제가 발생하는데, 해당 키를 가지고 그 어떤 행동도 할 수 있다는 것이다. 이 키는 권한이라는 개념이 없기에 유저의 모든 권한을 가지게 되고 따라서 이 키가 탈취된다는 것은 사용자의 모든 정보가 탈취된 것이라고 봐도 무방하다.

또 요즘과 같이 수많은 API 기반의 IT 서비스가 탄생하고 각 서비스들이 유기적으로 사용되는 경우는 매우 복잡한 인증들이 많이 필요하게 된다. 가령 우리가 흔히 쓰는 업무 툴인 지라만해도 지라에서 나의 구글드라이브에 접근할 권한을 주는 것 처럼 사용자의 특정 서비스에 대한 권한을 위임받는 것은 이제 매우 흔한 것이 되었다.

OAuth 는 이러한 형태의 인증의 새로운 규약을 제공하는데 이번 포스트에서는 내가 만든 어플리케이션이 내 어플리케이션 사용자의 구글 계정에 접근하고 이를 사용할 권한을 할당받아야 하는 경우이다.

일반적으로 생각하면 이를 위해서 가장 편한것은 유저에게 아이디와 비밀번호를 받아 내가 보관하는 것이 있겠다. 사실 개발자 입장에서는 매우 매력적으로 느껴지지만 사실 사용자의 개인정보는 탈탈 털렸고, 나는 사용자의 구글 드라이브의 사진 등 여러 중요 정보에 접근할 수 있을 것이다. 물론 이것은 심각한 상황이고 우리의 고객은 우리를 신뢰하지 않을것이고 신뢰해서도 안될 것이다.

이 경우 괜찮은 방법중 하나는 바로 우리가 “구글에 어떤 구글 유저가 우리에게 구글 API 를 사용할 권한을 주고 싶다던데 의심스러우면 너가 물어봐!” 라고 하는 방법이 있다. 구글이 직접 사용자에게 질문을 하고 사용자가 이를 허가한다면 이는 매우 바람직한 방법이 아닐 수 없다.

이 경우 문제가 하나 있는데 내가 구글에게 매번 사용자에게 물어봐! 라고 한다면 사용자와 구글은 매우 화가날 것이라는 것이다. 내가 사용자의 구글 드라이브를 사용할때마다 사용자에게 구글에게 답변을 해달라고 하는것은 정말이지 성가신 일이다.

그래서 OAuth 는 좋은 해결방법을 생각해 낸다. 바로 사용자가 구글에게 우리를 허가를 해주었다는 인증서를 발급하는 것이다. 이 인증서를 통해 우리는 구글에게 매번 특정 사용자의 권한을 입증할 수 있다. OAuth 에서 이러한 인증서를 access token 이라고 부른다.

하지만 만약 이 인증서가 바뀌지 않는다면 큰 보안 이슈가 있는데, 이 책임은 사실 우리가 져야 할 것이다. 유저는 우리를 믿고 자신의 구글 권한을 부여했는데, 우리가 이를 제대로 보관하지 못했기 때문이다. 여기서 좋은 해답이 하나 있는데 인증서가 계속 만료되게끔 하여 탈취되어도 보다 안전하게 하고 우리가 이를 갱신할 수 있는 별도의 인증서를 보관하는 것이다. 물론 이 인증서도 탈취될 수 있지만 구글은 이 인증서와 우리의 비밀번호를 받아 이를 인증하기 때문에 이것이 해킹당하려면 해커는 인증서를 갱신할 수 있는 토큰 (refresh token) 과 우리의 client secret 두가지를 모두 탈취해야 할 것이다.

따라서 OAuth는 이러한 문제를 잘 해결해 준다.

Google API 사용을 위한 OAuth 인증 절차

Google API 에서 OAuth 인증 절차는 다음과 같다.

구글에서 Client ID 와 Client Secret 를 매뉴얼하게 발급받는다. (이는 google api console 에서 할 수 있다.)

이 Client ID 는 나에게 부여되는 공유 번호이고, secret 으로 이를 증명할 수 있다.

우리는 구글에게 어떤 사용자의 권한을 원한다고 요청을 하면 구글은 자신이 만든 별도의 인증페이지로 고객을 보내고 고객이 여기서 자신이 맞다고 하면, 그 인증으로 authentication code 을 발급하여 우리가 전달한 redirect uri 로 요청을 보내준다. 우리는 이 token 을 구글에게 전달해서 access token 과 refresh 토큰을 발급할 수 있는 것이다.

이를 코드로 작성해 보자

먼저 구글에게 우리의 client id 와 원하는 권한의 범위를 정해서 전달한다.

1
2
3
4
5
https://accounts.google.com/o/oauth2/v2/auth?\
scope=https://www.googleapis.com/auth/analytics&\
redirect_uri=http://localhost:8080&\
client_id=<YOUR_CLIENT_ID>&\
response_type=code

여기서 query parameter 를 한번씩 살펴보면

scope : 어떤 resource 에 대한 권한을 받을 것인가

redirect_uri: 구글이 유저에게 확인을 한 뒤에 어디로 요청을 반환해줄 것인가

response_type: code 라고 써줘야 한다 뭔지 모름…

client_id: 내 어플리케이션이 발급받은 client id

사용자의 요청을 받아 저렇게 구글에 전달하면 구글은 별도의 prompt 를 띄워서 사용자에게 구글 계정을 인증할 것인지를 직접 묻게 된다. 사용자의 요청은 구글에게 전달이 되고, 구글은 사용자의 인증이 완료되면 위에서 우리 어플리케이션이 알려준 redirect_url 로 사용자의 authentication token 을 전달해 준다. 이 code를 다시 아래와 같이 우리의 client secret 과 함께 구글에 보내주면 우리는 비로소 access token 과 refresh token 을 발급받을 수 있다.

여기서 주의해야할 점은 redirect_url 에 명시된 호스트에서 응답을 받을 준비를 하고 받은 authentication code 를 다시 구글에 보내 access token 과 refresh 토큰을 발급해야 한다는 것이다.

1
curl +X POST <https://oauth2.googleapis.com/token?code=><당신의 인증 코드>&client_id=<당신의 클라이언트 아이디>&client_secret=<당신의 클라이언트 secret>&redirect_uri=http://localhost:8080&grant_type=authorization_code

code: authentication code

client_id: id of the application client

client_secret: you secret

redirect_uri

grant_type: hard code authorization_code which represents grant type

redirect_url 의 서버가 사용자의 authentication code 를 받아 위 요청을 보내면 access_token 과 refresh token 을 발급받을 수 있다.

추후에 access_token 이 만료된다면 refresh token 으로 아래처럼 새로운 access_token 을 발급받을 수 있는데 이를 통해 우리는 사용자에게 매번 구글 인증을 하도록 하지 않고 별도의 refresh 토큰을 잘 보관해두고 만료된 access_token 을 필요할 때마다 갱신해 줄 수 있다.

1
2
3
4
5
6
7
8
curl -X POST \\
<https://oauth2.googleapis.com/token> \\
-H 'Content-Type: application/x-www-form-urlencoded,multipart/form-data;' \\
-H 'content-type: multipart/form-data
-F client_id=client_id \\
-F client_secret=client_secret \\
-F refresh_token=refresh_token \\
-F grant_type=refresh_token

이렇게 발급받은 토큰을 Header 에 Authorization Bearer 방식으로 담아 보내면 우리는 드디어 구글 API 를 사용할 수 있게 된다!!

개요

소프트웨어 개발에서 CI/CD 란 Continuous Integration and Continuous delivery 의 약어로 다음과 같은 의미를 가집니다.

먼저, Continuous Integration 이란 여러 사람이 작업한 여러 작업 내용을 하나로 원활하게 병합하는 것을 의미합니다. 예를 들어 한 회사에서 3명의 개발자가 하나의 프로젝트를 개발한다면, 세 사람의 작업내용을 하나로 합치는 것은 매우 번거로운 일이 아닐 수 없습니다. 각 개발자 사이의 작업 내용이 겹칠 수도 있고, 다른 사람의 작업 결과가 또 다른 사람의 작업 내용에 변화를 미칠 수도 있습니다. 또, 각 개발자가 열심히 테스트코드를 작성해 두었다 한들 누군가 한명이 각 개발자의 변화된 개발분을 다운로드 해서 테스트 코드를 돌려보고 그 위에 자신의 개발분의 적용시켜 다음 테스트를 돌리는 등 여러 노력이 필요하게 됩니다.

현대 개발 패러다임에서는 이러한 코드 변화와 버전관리를 위한 여러 tool 이 존재하며, 가장 대표적인 버전관리 툴인 Git 을 예로 들어 설명을 하면, 각 개발자는 각각 자신의 feature 브랜치를 만들어 작업을 하고 이를 하나의 master 브랜치에 합치는 행위를 반복하는데, 각 commit 들이 안정적으로 master 에 반영된 것을 확인하기 위해서는 테스트코드를 돌려보는 등의 검증을 거쳐야 합니다.

Jenkins 는 이렇게 여러 branch 를 master 로 병합함에 있어, 테스트 코드 실행 linting 등 master 로 다른 변화들이 안정적으로 병합되기 위한 일련의 과정을 자동으로 처리하고 모든 commit 이 master 에 안정적으로 반영될 수 있게 도와줍니다.

그 다음으로 Continuous Delivery 란 이렇게 합쳐진 하나의 master 코드 베이스를 실제 사용자가 사용하는 production 환경에 쉽고 안정적으로 배포되게 하는 것을 말합니다.

가령, 소프트 웨어의 배포에는 여러 활동이 포함될 수 있는데, 각 소스코드를 빌드하는 것은 기본이고, 빌드된 바이너리 파일 혹은 docker image 등을 실제 production 환경에 배포하는 것은 규모가 큰 서비스 에서는 수십대의 서버의 프로세스를 교체해 주어야 하며, 또 그 모든 과정에 있어 사용자가 서비스를 이용함에 불편함이 없도록 안정적으로 이루어 져야 합니다. Jenkins 는 이렇게 배포될 소프트웨어를 실제 환경에 안정적으로 배포하기 위한 다양한 기능을 제공합니다.

이번 포스트에서는 Git 과 Jenkins 를 활용하여 아주 기본적인 Continuous Integration 파이프라인을 구축해 보도록 할 것이며, 그 과정은 다음과 같습니다.

  1. Feature 브랜치에 코드를 작성합니다.
    이 코드에는 단순히 서비스 로직 뿐만 아니라 Jenkins 가 실행시킬 테스트코드와 Linting rule 또한 포함이 되어야 합니다.
  2. Master 브랜치에 Feature 브랜치를 머지합니다.
    브랜치가 merge 되면, Jenkins 는 github 에서 이 사실을 듣고, git 소스코드를 다운로드 받아 테스트코드와 lint 를 실행합니다.
  3. 코드가 안정적으로 병합되었다면, Jenkins 는 소스코드를 빌드하고 ( 이번 포스트에서는 docker container 를 활용한 배포를 가정하므로 docker image 를 생성합니다 ) 서버에게 이 이미지를 다운로드 받아 실행하게 합니다.

AWS EC2 Instance 에 Jenkins 설치하기

먼저 이 모든 CI/CD 작업을 수행할 Jenkins Server 를 만들어 봅시다.

AWS 에서 Amazon Linux 기반의 인스턴스 하나를 생성하고 다음과 같은 script 를 통해 Jenkins 를 설치합니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
sudo yum update -y

# Jenkins 는 Java 8 runtime 위에서 실행되므로 java open jdk 를 먼저 설치해 줍니다.
sudo yum install -y java-1.8.0-openjdk wget

# Jenkins 설치
wget http://mirrors.jenkins.io/war-stable/latest/jenkins.war

# Jenkins 가 사용할 docker 와 git 을 설치해 줍니다.
sudo yum install -y jenkins git docker
java -jar jenkins.war --httpPort=8080

# Git configuration
sudo -u jenkins git config --global credential.helper '!aws codecommit credential-helper $@'
sudo -u jenkins git config --global credential.useHttpPath true
sudo -u jenkins git config --global user.name 'jenkins-workder'

# Start docker machine
sudo chmod 666 /var/run/docker.sock
sudo service docker start

# Add jenkins user in docker group so that jenkins user can use docker machine
groupadd docker
sudo usermod -aG docker jenkins

# You should restart jenkins to apply updated user group
sudo service jenkins restart

Jenkins 설정하기

위처럼 Jenkins 를 설치하고 Jenkins server 를 생행했다면, http://localhost:8080 에 jenkins dashboard 가 열리게 됩니다.

본 dashboard 에서 jenkins 를 설정하면되며, 초기 비밀번호는 /var/lib/jenkins/secrets/initailAdminPassword 에 위치해 있다.

AWS configuration

Jenkins 가 was 를 사용하기 위해 다음과 같이 AWS 계정 설정을 해준다.

1
sudo -u jenkins aws configure
1
2
3
4
5
6
7
8
9
echo "AWS_ACCESS_KEY=123456789">>~/.bash_profile
echo "AWS_SECRET_ACCESS_KEY=123456789">>~/.bash_profile
echo "AWS_DEFAULT_REGION=123456789">>~/.bash_profile

sudo mkdir /var/lib/jenkins/.aws
sudo touch /var/lib/jenkins/.aws/credentials
sudo echo "[default]" >> /var/lib/jenkins/.aws/credentials
sudo echo "aws_access_key_id=123456789" >> /var/lib/jenkins/.aws/credentials
sudo echo "aws_secret_access_key=123456789" >> /var/lib/jenkins/.aws/credentials

만약 jenkins 에서 aws cli 를 사용하는 경우 aws credential을 /var/lib/jenkins/.aws/credentials 에서 찾기 때문에 해당 파일에도 credentials 을 위치시켜야 한다.

jenkins 설정에서도 위의 Environment Variables 를 설정해 준다.

Jenkins node 가 ecr 을 사용할 수 있도록 다음 명령어를 실행한다.

1
$(aws ecr get-login --no-include-email)

만약 git repository 대신 AWS codecommit repository 를 사용한다면, 해당 key 를 AWS IAM user 탭에서 code commit http 설정을 할 수 있다.

Git configuration

Jenkins 가 git 을 사용하기 위해 다음과 같이 git 설정을 해준다.

1
2
3
4
5
6
cd ~jenkins

sudo -u jenkins git config --global credential.helper '!aws codecommit credential-helper $@'
sudo -u jenkins git config --global credential.useHttpPath true
sudo -u jenkins git config --global user.email "me@mycompany.com"
sudo -u jenkins git config --global user.name "MyjenkinsServer"

또한 jenkins 가 private repository 에 접근하려면, git credential 을 jenkins 에 등록해 주어야 하며 이는 jenkins configuration 의 credential 세팅에서 해줄 수 있다.

Jenkins migration guide

Jenkins 를 설치운영할때 Jenkins 서버를 migrate 할 필요성이 생길 수 있다.

Jenkin 의 모든 설정을 GUI 를 통해 했기 때문에, 모든 과정을 반복하는 것은 정말 성가신 일이 아닐 수 없다.

Jenkins 는 모든 설정을 파일 시스템에 저장하기 때문에, Jenkins directory 의 data 들만 잘 이동해 주면, 모든 설정 정보를 안전하고 편리하게 이관할 수 있으며, 그 위치는 /var/lib/jenkins 에 있다.

주의 사항

여기서 주의할 사항이 있는데, Jenkins directory 는 system directory 이므로 mv 명령이 제대로 수행되지 않는 경우가 있다.

때문에, 파일을 복사하기 앞서 directory 권한을 알맞게 변경해 주어야 한다. 또한, 복사한 파일의 user 와 group 이 linux user 로 변경되므로 반드시 복사 이후에 올바른 file owner 인 jenkins 로 변경해 주어야 하는데, 이는 다음의 명령어로 해결할 수 있다.

1
2
3
# jenkins:jenkins 사용자:그룹
# -R recursive
sudo chown -R jenkins:jenkins /var/lib/jenkins

Installation

1
sudo apt-get install git-all

Terminology

Branch 란 commit 의 나열을 의미한다. 서로 다른 branch 란 서로 다른 작업 내역의 합이고 이러한 작업내역을 서로 합치고 변경하면서 여러 형태의 code base 가 존재할 수 있다.

Commit 이란 code base 의 변화내역을 의미한다. 즉, git 에서 현재 code base 의 최종상태는 과거의 commit 들의 합을 의미하고, 특정 commit 을 변경하는 행위는 과거의 특정 시점의 작업 내용을 변경함을 의미한다. git 에서 이러한 commit 은 매우 핵심적인 역할을 한다.

HEAD 현재 내가 있는 commit 을 의미한다. 내가 현재 있는 곳은 사용자에게 매우 직관적이기에 git 에서는 특정 commit 의 고유한 identity 인 commit hash 대신에 HEAD 를 기준으로 commit hash 를 표현하는 경우가 많다. 가령 HEAD~3 이란 현재 내가 있는 commit 으로부터 앞에서 3번째 커밋의 hash 를 가리킨다.

Setup

Global setup

git 의 사용자 정보 및 사용자별 다른 연결 정보등과 같은 공통의 설정들은 <home>/.gitconfig 파일에 설정할 수 있다.

이는 git config --global user.name = <USER_NAME> 등과 같은 명령어를 통해서도 가능하지만 파일에 직접 설정을 작성할 수 있다.

~/.gitconfig

1
2
3
4
5
6
7
8
9
10
11
12
13
[user]
name = <사용자 이름>
email = <사용자 이메일>
username = <USER_NAME>

[credential]
helper = cache # 비밀번호를 캐싱하여 계속 입력하지 않아도 되도록 한다.

# 특정 repository 에 대한 credential 을 설정한다.
# 예를 들어 만약 코드 커밋을 사용한다면 다음과 같이 code commit repository 세팅을 다음과 같이 할 수 있다.
[credential "<CODE_COMMIT_REPOSITORY>"]
helper = !aws codecommit credential-helper $@
UseHttpPath = true

위 설정은 간단히 아래의 커맨드로도 가능하다.

1
2
3
4
git config --global user.name <USER_NAME>
git config --global user.email <USER_EMAIL>
git config credential.helper cache
git config --list # 설정한 내용 확인

Repository level setup

위처럼 git 의 system 전역 세팅이 아닌 특정 git repository 마다 다른 세팅을 하고자 한다면 다음과 같은 레포지토리 마다 설정을 해줄 수 있다.

특정 repository 의 .git 디렉토리의 config 파일에 git 세팅을 할 수 있다.

SSH setup

Git repository 에 인증체계는 https 방식과 ssh 방식이 있는데, https 방식은 유저네임과 패스워드로 레포지토리 인증을 하는 것이고, ssh 방식에서는 사용자 pc 의 ssh 공개키를 github repository 에 등록하여 인증을 하는 방식이다.

먼저 ssh 인증 방식은 다음과 같다.

먼저, ssh를 활용하여 연결하기 위해서 컴퓨터의 ssh key를 생성하고, 생성된 공개키는 git에 등록한다.
공개키를 사용하려면 일단 공개키를 만들어야 하는데, 공개키를 만드는 방법은 모든 운영체제가 비슷하다.
먼저 키가 있는지부터 확인하자. 사용자의 SSH 키들은 기본적으로 사용자의 ~/.ssh 디렉토리에 저장한다.

리눅스 혹은 ubuntu의 경우 ssh-keygen을 통해 공개키/개인키 쌍을 생성할 수 있다.

1
ssh-keygen

위 명령어를 통해 공개키를 생성하였으면 ~/.ssh 디렉토리에 id_rsa.pub가 생성되었을 것이다.
해당 공개키를 git 홈페이지의 repository의 설정에서 등록해 주면 된다.

참조

Git Add

추가된 파일 포함시키고 커밋하기

1
2
3
4
5
### 모든 파일 추가
git add .

# 특정 파일 추가
git add <FILE_NAME>

branch

브랜치 생성 및 변경

1
2
git branch [브랜치명]
git checkout [브랜치명]

git branch [브랜치명] 명령어로 브랜치를 생성하고
git checkout [브랜치명] 명령어를 통해 브랜치를 변경한다.
여기서 checkout은 단순히 브랜치를 옮기는 것으로 지금까지의 변경내용이 바뀌지 않고 해당 브랜치로 이동하기 때문에
해당 브랜치에 지금의 변경내용이 전부 반영된다.

브랜치 삭제하기

git branch -d [branch Name]

commit

1
2
# 커밋하기
git commit -m "메세지"

checkout

Checkout 명령어는 현재 나의 code base 를 특정 커밋 혹은 브랜치로 옮기는 것이다.

사실 더 정확한 표현은 특정 커밋으로 옮긴다고 하는 것이 맞는 표현일 것 같다.

1
2
3
4
5
6
7
8
9
10
# 특정 브랜치로 code base 이동
# 사실 특정 브랜치 이름은 특정 커밋 해쉬를 의미한다.
# 해당 브랜치의 마지막 commit 으로 이동한다고 보면 된다.
git checkout <BRANCH_NAME>

# 특정 커밋으로 code base 이동
git checkout <COMMIT_HASH>

# 특정 파일만 특정 commit 으로 이동
git checkout <COMMIT_HASH> <FILE_NAME>

원격 브랜치 가져오기

git checkout -t origin/eventsource

###

log

먼저 커밋 내역을 확인할 수 있도록 log를 확인한다.

1
git log

merge

머지하기
git checkout master를 통해 마스터로 이동한다
git merge [commit name]

push

원격 코드베이스에 나의 코드를 밀어넣는다.

업스트림(upstream) 브랜치 설정
로컬 저장소를 init 명령어로 생성했을땐 수동으로 업스트림 브랜치를 설정할 필요가 있다. 업스트림 브랜치란 원격 저장소와 바로 연결된 로컬 저장소를 말하며 push나 pull 명령등에서 원격 저장소 이름을 생략할 수 있게 한다.

1
git push --set-upstream origin master

밀어넣기
git push origin [branch]

강제로 밀어넣기
git push -u origin master

pull

풀받기
git pull [remote 저장소] [브랜치]

rebase

Rebase 란 말 그대로 시작점을 다시 설정하는 것이다.

git 의 코드관리는 복잡해 보이지만 기본적으로 최초의 하나의 뿌리에서 부터 여러 갈래로 갈라져 나간 나무의 형태를 띄고 있다. 여기서 rebase 의 의미는 현재 나의 branch 와 합치고 싶은 다른 branch 의 base 즉 갈라져 나온 최초의 commit 시점을 찾아서 그 이후로 진행한 나의 모든 가지를 통으로 잘라서 다른 branch 의 끝으로 옮겨붙이는 것이다.

실제 나무에서 하나의 가지를 통으로 잘라내어 붙이고 싶은 가지를 선택해 그 가지의 끝에 잘라낸 가지를 옮겨붙이는 것을 생각하면 쉽게 이해할 수 있다.

이러한 rebase 는 상대방의 모든 코드 변화 이후에 나의 코드변화를 빠짐없이 적용할 수 있다는 점에서 매우 유용하다.

가령 친구와 나의 교과서 필기를 하나로 합치고 싶은데 제일 깔끔한 친구의 노트에 내 모든 필기내용을 한반에 옮겨적는 것을 생각해 보면 된다. 이 얼마나 편리한가! 만약 여기서 친구와 내가 같은 페이지에 다른 내용을 기록했다면 여기서 어떤 내용을 최종으로 작성할지 결정하는 작업이 필요하다.

과거 나의 커밋 내용을 수정하기

open source 활동을 하거나 혹은 대규모의 프로젝트를 진행할때 겪는 가장 큰 문제는 내가 작성한 과거의 코드내용, 즉 과거의 커밋 내용을 수정하는 것이다.

대부분의 경우 feature 브랜치에서 많은 내용을 수정하고 중간중간 변경 사항에 대해 commit 으로 기록하기 때문에 과거의 커밋을 바꾸기 위해서는 까마득한 예전의 코드로 돌아가 그 특정 부분을 수정하고 그 뒤의 변경사항을 다시 재적용 시키는 일이 필요하다.

이 경우에는 git rebase 명령을 사용하여 해결할 수 있으며 다음과 같은 절차를 거친다.

  1. git log 를 통해 나의 이전 커밋 내용을 확인한다.
  2. git rebase -i HEAD~n 를 통해 HEAD로 부터 얼마나 뒤 내용을 수정하고 rebase를 진행할지 정해준다. 가령 HEAD 로 부터 3 번째 커밋부터의 커밋들에 수정사항이 있다면 git rebase -i HEAD~3 명령어를 입력한다.
  3. 위 명령어를 입력하면 과거의 커밋들이 나타나고 커밋명 앞에 pick 이라는 키워드가 있다. 여기서 우리가 수정하기를 원하는 커밋의 pick 키워드를 e(edit) 으로 바꿔준다.
  4. 이제 git이 edit 하고자 하는 커밋으로 코드를 돌려주고 원하는 내용을 수정한 뒤에 git commit --amend 를 해주면 해당 커밋을 수정하여 다시 커밋하고 git rebase --continue 명령을 통해 뒤의 커밋들을 쭉 적용시켜 줄 수 있다.

remote

원격 레포지토리 등록하기

원격 저장소와 코드를 주고 받기 위해 가장 먼저 해야 할 일은 원격 저장소가 어디에 있는지를 알려주는 일이다.
다음과 같은 코드를 입력하기 원격저장소 origin의 위치를 등록해 준다.

1
git remote add origin <GIT_REPOSITORY>

revert

이번에는 기존에 한 커밋을 되돌리는 법을 배운다.

뒤로 돌리기

1
git revert HEAD

명령어를 통해 HEAD에 마지막으로 커밋된 내용을 뒤로 돌린다.

이 revert 에서 주의할 점은 해당 커밋의 변경내용을 정확히 반대로 하는 새로운 commit 을 만들어 내는 것이다.

즉, revert 를 하면 revert 하고싶은 commit 을 뒤로 돌리는 새로운 업데이트에 대한 commit 을 만들어 낸다.

stash

로컬 작업 내용 버리기 혹은 저장하기

당신이 어떤 프로젝트에서 한 부분을 담당하고 있다고 하자. 그리고 여기에서 뭔가 작업하던 일이 있고 다른 요청이 들어와서 잠시 브랜치를 변경해야 할 일이 생겼다고 치자. 아직 완료하지 않은 일을 커밋하는 것은 좀 껄끄럽다. 이런 상황에서는 커밋하지 않고 나중에 다시 돌아와서 작업을 다시 하고 싶을 것이다. 이 문제는 git stash라는 명령으로 해결할 수 있다.

1
2
3
4
5
git stash // stash difference
git stash clear // deled stased
git stash list // list up stashed
# stash 한 변경 내용들 불러오기
git stash pop

##

Configuration

Repository wide ssh setup

아래 명령어는 특정 레포지토리의 ssh 인증키를 별도로 세팅하는 코드이다. 이를 통해 여러개의 레포지토리 마다 별도의 ssh 인증키를 사용할 수 있다. 개인 pc 에서 업무용 repository 에 접근하는 경우라면 이러한 세팅은 매우 편리하다.

아래 명령어를 git repository 에서 실행함으로 간편하게 repository level 에서의 인증키를 등록할 수 있고

1
git config --local --add core.sshCommand 'ssh -i ~/your_key'

혹은 아래와 같이 직접 .git/config 파일을 수정할 수 있다.

1
2
[core]
sshCommand = "ssh -i ~/.ssh/<KEY_FILE>"

git home 디렉토리 변경하기

git 아이콘을 우클릭하여 대상 뒤의 –cd-home을 없애고

시작위치에 원하는 위치를 넣어준다.

CLI 에서 비밀번호 저장하기

git config credential.helper store

2FA 인증

git authentication

git 에서 2FA 인증을 하는 경우 personal access token을 발급받아서 해야한다.

Prerequisite

Install

1
curl https://sdk.cloud.google.com | bash

login

1
2
3
gcloud auth login
gcloud auth login --no-launch-browser # no browser
gcloud config list project

set project

1
2
gcloud config set project <PROJECT_ID>
gcloud config list project # list project

install kubernetese

1
curl -sS https://get.k8s.io | bash

WAF stands for website application firewall

A WAF keeps the malicious traffic off your website

how does it works?

the waf works as a vaccine for a website.

application firewalls go beyond the metadata of the packets transferred at the network level.

they focus on the data in transfer.

Cloudfront sms 정적, 동적 웹 콘텐츠를 빠르게 distribute 하기 위한 서비스이다.

이를 위해 aws 는 edge location 이라는 데이터 센터의 네트워크에 사용자의 데이터를 보관한다.

여기서 제일 빠르게 배포될 수 있는 edge location 으로 route 된다.

만약 해당하는 edge location 에 파일이 없다면, cloudfront 는 원본 위치에서 파일을 가져온다.

cloudfront 를 사용하지 않으면 네트워크는 해당 파일이 어디에 있는지 모르기 때문에 여러 네트워크를 경유해서 낮은 latency 를 가지게 된다.

당시의 파일은 여러개의 edge location 에 복사되어 저장된다.

How to setup

  1. specify origin server like s3 ec2 etc…

  2. upload file to origin server
    including web pages, fines,

    if you use s3bucket make it public

  3. create cloudfron distribution

  4. Cloudfron assigns a domain name to you new distribution that you can see in cloudformation console

  5. edge locations which is collections of servers in geographically dispersed data centers copies of your objects

시장의 왜곡에서 기회를 잡아라

시장에 대한 대중의 잘못된 판단으로 오평가된 기업을 찾아라

시장은 합리적인 사람들이 모여있는 곳이 아니다. 가령 특정 기사로 인해 잘못된 관념으로 주가가 폭락, 폭등 할 수 있다. 하나의 좋은 예는 바로 월드 트레이드 테러가 일어난 2001년 전 세계 보험 주식은 보상금에 대한 우려로 폭락하였고 이는 우리나라도 마찬가지 였다. 우리 나라의 ‘대한재보험’의 경우 테러 이후 주가가 하한가를 찍을만큼 주가가 폭등하였는데, 이는 미국 보험사와 국내 보험사에 관계가 있지 않을까 하는 대중의 막연한 추측 때문이었고, 실제로는 아무 관계가 없었다. 오히려 국내 보험시장은 해외의 테러 사테를 본 뒤 보험의 필요성을 느껴 보험을 가입하는 많은 사람들 때문에 수익성이 개선되었다. 머지 않아 해당 보험사의 주가를 원래 가격을 되찾았으며, 시장의 왜곡을 눈치챈 사람들은 저평가된 주식을 매수하여 큰 수익을 올렸다.

폭락하는 주식을 눈여겨 보라, 대중의 오해로 인한 시장의 왜곡이 존재하지 않는가?

재정의형 기업

사업을 재정의 한다는 것은 그 기업이 하고 있는 사업은 변함이 없지만 그 기업의 경쟁우위와 본질을 파악하여 재정의 하는 것이다. 가령 나이키의 경우 대부분의 사람들은 그저 그런 신발 가게라고 생각했을 것이다. 하지만 나이키의 운영방식을 잘 알아본 사람들은 나이키는 오히려 신발의 생산에는 거의 관여하지 않고 브랜드와 디자인만을 담당하는 마케팅 기업이라는 사실을 눈치챘을 것이다. 이런 가치를 알아본 사람들은 나이키에 투자했고, 막대한 투자수익을 거둘 수 있었을 것이다.

과거 ‘동양제과’ 의 사례를 살펴보면 ‘동양제과’ 는 대형 미디어 그룹의 지주회사로 재평가 되어야 한다.

‘동양제과’ 는 바둑 TV 와 OCN, 투니버스 등 방송사의 지주회사이며, 해당 업체들을 흑자로 잘 운영되고 있다. 이 경우 투자자들은 기존 ‘동양제과’ 가 하던 사업을 넘어서 소속 기업들의 영업실적이 지주회사인 ‘동양제과’ 에 어떤 영향을 미칠지 잘 판단해야 한다.

이러한 재정의 기업들을 물색하기 위해서는 어떻게 해야 할까?

사실 이런 재정의형 기업의 경우 기업이 행보에 관심을 가지지 않으면, 이를 잘 알기 어렵다. 이 경우 각종 기사를 통해 경영 성과에 긍정적인 변화가 있는 기업들의 모회사를 조사하거나, 어떤 회사가 기존에 하지 않던 새로운 신사업을 시작한다던가 하는 기업의 중대한 경영 방침들을 지속적으로 트래킹 해야 한다.

만약 관심가는 산업분야가 있다면, 해당 산업의 주요 기업들의 사업의 방향을 잘 따라가다 보면 좋은 기회를 얻을 수 있다.

업계의 경기는 개별 기업의 경기와 다를 수 있다.

또한 산업 자체가 사양산업이라 불리는 경우 많은 투자자들은 사양산업에 속한 기업들의 주식을 팔아치우는 현상이 생기게 된다. 하지만, 산업군과 기업은 엄연히 다르다. 특히 성장형 산업의 경우 수많은 업체들이 들어오는 반면 사양산업은 새로운 업체가 들어오지 않을 확률이 높고 특정 제품군이 나머지 업체를 흡수하여 winner takes all 구조를 보이는 경우가 많다.

요즘 시대의 경우 대부분의 신사업들을 AI 와 블록체인들 소프트웨어 기반의 지식산업으로 그 무게가 이동하고 있기에, 기존의 중공업과 같은 업계는 이제 한물 갔다는 풍조가 강해지고 있다. 또, 국내 반도체 실적 전망과 부품업계의 소식을 접한다면 해당 업계의 모든 기업들에 대한 부정적인 이미지를 가지기 쉽다. 때문에 이러한 업계의 불황은 대부분의 투자자들이 거짓 위험을 감지하게 만들고 훌륭한 펀더멘탈을 가진 기업들이 저평가되게 만들며, 훌륭한 투자자라면 옥석을 가려 매수할 기회를 보아야 할 것이다.

=> 사양산업 군에서 독보적으로 영업이익률을 높여가는 기업의 원인을 분석하라.

경기침체는 많은 사람들의 오해를 산다.

경기침체가 오고 경기가 불황이면 사람들은 많은 주식을 팔아치운다. 이 경우 그 기업의 영업성적과는 관계없이 비정상적인 주가하락이 발생하는데 이 시기야 말로 매수시기이다.

가령 1998년 IMF 시기에도 현대백화점의 영업이익은 꾸준히 전년대비 2배 이상 늘었으나, 주가는 폭락했다. 합리적인 투자자라면 이 기회를 잘 활용했을 것이다.

영업성적이 좋은데도 PER 가 그대로라면?

주식을 누가 들고 있는가는 매우 중요하다. 가령 어떤 회사의 영업이익이 아무리 좋아도, PER 가 늘지 않는다면 그 주식의 보유자와 거래량을 체크하라. 만약 대부분의 주식이 전문 투자사나 특수지분으로 편성되어 있다면, 주식의 거래량이 크게 변할 수 없고, 그만큼 PER 의 변동성도 작다.

하지만 이 경우 장기간에 걸쳐 주가가 반영되지 않을수는 없다. 이런 기업은 어느 순간 거래량이 발생하고 그 잠재력을 발산할 것이다. 갑자기 오는 주가 상승의 기회를 포착해야 한다.

독점 기업을 발굴하라

독점기업은 정부의 입장에서 보면 사회 전체의 이익에 반하는 행동을 할 수 있다는 점에서 제재의 대상이 될 수 있지만, 투자자의 입장에서 보면 상당히 매력적인 기업이다. 이런 기업은 마케팅 비용을 줄여 영업 이익을 극대화 할 수 있으면, 다른 대안이 없고 다른 모든 사람이 사용하기 때문에 가격 인상을 통해 추가적인 영업이익 확보도 가능하다.

독점기업을 찾는 방법은 상당히 단순한데, 주변에서 그 제품을 좋아하지 않음에도 불구하고 어쩔수없이 구매해야 하는 제품들을 찾는 것이다. 가령 내가 ms 의 워드 프로그램을 사용하기 싫더라도 다른 모든 사람들이 문서 프로그램으로 워드를 사용하기 때문에 어쩔수 없이 구매해야 한다.

자연 독점형 기업

먼저 독점 기업 중에서 인위적으로 독점기업이 된 경우가 아닌 자연적으로 독점 지위를 누리게 된 ‘자연 독점형 기업’ 으로 기 범위를 제한한다.

가령, 한전과 같이 정부차원에서 라이센스를 부과한다던가 하는 사유로 독점적 지위를 누리게 된 기업은 정부나 혹은 경제 상황에 따라 그 독점 지위가 존속 가능하지 않을 수 있기 때문에, 이는 배제한다.

이러한 자연독점형 기업들은 몇가지 종류로 나눌수가 있는데, 그 종류는 표준화로 인한 독점, 기술적 독점, 마케팅 독점, 규모의 독점, 경쟁사 몰락으로 인한 독점의 경우가 있다.

표준화

먼저 표준화 독점이란, 특정 제품이 이미 그 서비스의 표준이 되어 내가 사용하고 싶지 않아도 다른 많은 사람들이 사용하기 때문에 어쩔 수 없이 사용해야 하는 제품을 의미한다.

가령 마이크로 소프트의 워드, 엑셀과 같은 프로그램은 내가 아무리 다른 문서 에디터를 사용하고 싶다 하더라도 그 문서를 함께 공유하는 모든 사람들이 이미 마이크로소프트의 제품을 사용하기 때문에, 어쩔 수 없이 사용해야 하는데, 이것이 가장 대표적인 표준화 독점의 사례이다.

필자가 생각하는 국내의 표준화 독과점 기업 중 하나는 리디북스 이다. 리디북스 는 이미 전자책 시장의 60% 를 장악하고 있으며, 필자 또한 리디북스 전자책 단말기의 사용자이다. 리디북스는 다른 전자책 플랫폼과 다르게 타 서비스의 기기에 호환되지 않고, 독자적인 DRM 이 들어가기 때문에, 한번 리디북스 책을 구매했다면, 그 유저는 큰 문제가 있지 않는 한, 계속해서 리디북스에서 전자책을 구매하게 된다. 또한 리디는 도서 정액제 서비스등 유저를 묶어들 많은 서비스들을 내놓고 있으며, 이는 그 독과점 지위를 유지할 수 있는 큰 해자가 된다. 또한, 리디북스의 단말기는 현 유저들에게 많은 사랑을 받고 있으며, 기존에 전자책을 보급하던 많은 업체들(YES24 를 비롯한 대형 서점들) 의 경우 전자책을 판매하고 있지만, 전자책을 읽을 수 있는 디바이스나 어플리케이션들이 비교적 열악하기에 많은 고객이 이탈하여 리디북스로 올 것이라 예상한다.

현재 리디북스의 재무현황의 경우 아직까지 매년 영업 손실을 내고 있지만, 향후 전자책 시장이 성장할 경우 점유율 60% 를 점유중인 리디북스의 영업이익은 꾸준히 성장할 것으로 판단되며, 전자책 공급업의 특성상 연구 개발비를 비롯한 각종 판관비를 매출 증가량에 비해 다소 낮은 비율로 증가할 것으로 예상되기에 영업 성과가 개선될 것으로 판단된다.

하지만, 현재 리디북스는 비상장 기업 으로 주식시장에서 거래가 불가능하여, 주식을 구매하기 위해서는 장외주식을 구매하거나 상장할 때까지 기다리는 것 외에는 매수가 불가능 하다.

기술적 독점

기술적 독점은 기업의 뛰어난 기술을 기반으로한 특허 등의 장치로 말미암아 다른 기업이 따라올 수 없는 기술력을 가지는 경우이다. 예로는 비아그라나 퀄컴의 CDMA 칩 등이 있다. 이러한 제품들은 다른 기업이 만들고자 해도 기술력 부족과 특허 문제로 제작이 불가능 하기 때문에, 해당 제품을 독점할 수 있다.

마케팅 독점

마케팅 독점이란 넓은 유통망을 기반으로한 브랜드 효과로 독점을 누리고 있는 기업이다.

가령 코카콜라나 맥도날드 등의 기업들은 전 세계적인 유통망으로 원가절감을 비롯한 규모의 경제를 누릴 뿐 아니라, 그 브랜드 파워로 인해 소비자들과 좋은 관계를 유지합니다. 이러한 마케팅 파워는 그 자체로 막대한 독점적 지위를 가지게 됩니다.

국내에 이런 마케팅 파워를 통한 브랜드가 있다면, 바로 백종원씨의 더본 코리아가 아닐까 싶습니다. 더본 코리아는 수십개의 프랜차이즈를 운영하고 있으며, 각 프랜차이즈는 백종원의 브랜드를 달고 소비자에게 다가가며, 소비자는 ‘백종원’ 이라는 이름을 믿고 매장에 방문하게 됩니다. 또, 백종원씨가 최근 많은 TV 프로그램에 나오면서, 소비자들에 대한 마케팅 파워를 강화했으며, 그 효과는 그대로 영업 실적에 반영되어 매년 영업이익이 폭발적으로 성장하고 있습니다.

백종원씨의 더본 코리아는 현재 요식업 뿐만이 아니라 호텔 사업등 다양한 라이프 스타일 브랜드를 운영하고 수익을 낼 것으로 보이며, 더본 코리아의 상장 유무에 많은 투자자들의 관심이 집중되고 있습니다.

규모의 독점

막대한 설비 투자처럼 큰 자본을 들여서 생산 환경을 구축해야 하는 사업의 경우 다른 기업이 참여하기 힘들다.

가령 삼성의 반도체라인의 경우 막대한 반도체 공정을 위한 설비투자가 선행되어야 하며, 이는 다른 기업이 들어오지 못하는 큰 독점적 지위를 발생시킨다.

현재 중국의 경우처럼 국가 단위로 설비 투자에 자금을 투입하는 등의 막대한 투자가 뒷바침 되지 않는 이상 삼성전자의 반도체를 꺾는 것은 매우 어렵다.

경쟁사 몰락

지역 독점형 기업

일류 제품형 기업

###

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×