iwinv(가상호스팅)에 docker 적용하기

iwinv(가상호스팅)에 docker 적용하기

iwinv 제가 호스팅을 이전했다는 사실은 지난 글에서 이미 언급한 적이 있습니다.

오늘은 iwinv 로 이전하면서 엄청난 고생을 했던 경험에 대한 이야기 및 해결책에 대한 이야기를 적어 보려 합니다.

Environment

  • Ubuntu 16.04 xenial

삽질의 시작

IwinV Manual

iwinv 홈페이지를 가면 이렇게 도커 적용을 하는 것에 대한 매뉴얼이 있습니다만…

가격의 매리트와 docker 적용에 대한 호기심으로 시작한 이 작업이 이렇게 크나큰 고통을 안겨 줄 것이라는 것을 이 때는 몰랐습니다.

사실 저 메뉴얼이 있는걸 확인 하고 docker 적용에 별 어려움이 없을 것이라고 판단했던 것이 제가 서버 이전을 마음 먹은 것에 큰 이유 중 하나이기도 합니다.
물론 iwinv의 메뉴얼은 저를 속였습니다. (물론 회사가 의도친 않았지만…)ㅎㅎㅎ

이유인 즉, 저 매뉴얼은 반 쪽짜리 매뉴얼 이었기 때문입니다.

물론 간단히 하나의 도커파일만으로 사용할 경우는 별 문제가 없을 지도 모르겠습니다만,
도커 이미지간에 네트웍 통신에는 치명적 문제가 있었습니다.

MTU

위의 매뉴얼 링크를 클릭해보시면 아시겠지만, iwinv는 내부적으로 MTU1450으로 사용하고 있다고 합니다. 이리하여 도커의 MTU 설정을 변경해줘야 한다는 것이 저 글의 요지입니다.

자, 그럼 MTU가 무엇이냐하면,

컴퓨터 네트워킹에서, 레이어의 커뮤니케이션 프로토콜의 최대 전송 단위(maximum transmission unit, MTU)란 해당 레이어가 전송할 수 있는 최대 프로토콜 데이터 단위의 크기(바이트)이다.

최대 전송 단위 – 위키백과, 우리 모두의 백과사전

간단히 말해 네트워크 통신에서의 패킷 사이즈를 결정하는 단위라고 생각하면 될 듯 합니다.

이때는 “아 패킷 사이즈를 iwinv가 적게 쓰는 구나.” 하고 넘어갔습니다.

Docker 설치

매뉴얼대로 도커를 설치합니다.
물론 이 포스팅에서는 매뉴얼과 docker 홈페이지를 적절히 이용해서 설치하겠습니다.
현 시점에서의 설치방법입니다. (2017.6)

먼저 apt-get 업데이트를 합니다.

$ sudo apt-get update
$ sudo apt-get upgrade

도커 설치는 공식페이지를 참고합니다.

오래된 버전의 docker 가 있다면 지웁니다.

$ sudo apt-get remove docker docker-engine

docker 설치에 필요한 패키지를 설치합니다.

$ sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
software-properties-common

docker 의 공식 GPG key를 추가합니다.

$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

키를 확인합니다.
9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88

$ sudo apt-key fingerprint 0EBFCD88

pub 4096R/0EBFCD88 2017-02-22
Key fingerprint = 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88
uid Docker Release (CE deb) <docker@docker.com>
sub 4096R/F273FCD8 2017-02-22

amd64 architecture 를 사용하는 docker 를 설치하겠습니다.

$ sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"

Docker 가 설치가 잘 되었는지 확인

$ sudo docker run hello-world

...
Hello from Docker!
This message shows that your installation appears to be working correctly.

여기서부터 iwinv의 메뉴얼을 따릅니다.

$ sudo docker pull ubuntu
$ sudo docker run -it ubuntu

※ update가 진행이 안되는 문제 발생하며 ftp 등 일부 서비스에서 문제 발생.

위 증상은 MTU 때문입니다.
이제 MTU를 1450으로 세팅합니다.

$ cp /lib/systemd/system/docker.service /etc/systemd/system/docker.service
$ vi /etc/systemd/system/docker.service

/etc/systemd/system/docker.service

[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network.target docker.socket firewalld.service
Requires=docker.socket

[Service]
Type=notify
# the default is not to use systemd for cgroups because the delegate issues still
# exists and systemd currently does not support the cgroup feature set required
# for containers run by docker
ExecStart=/usr/bin/dockerd -H fd:// --mtu=1450
#-H fd://
ExecReload=/bin/kill -s HUP $MAINPID
LimitNOFILE=1048576
# Having non-zero Limit*s causes performance problems due to accounting overhead
# in the kernel. We recommend using cgroups to do container-local accounting.
LimitNPROC=infinity
LimitCORE=infinity
# Uncomment TasksMax if your systemd version supports it.
# Only systemd 226 and above support this version.
TasksMax=infinity
TimeoutStartSec=0
# set delegate yes so that systemd does not reset the cgroups of docker containers
Delegate=yes
# kill only the docker process, not all processes in the cgroup
KillMode=process

[Install]
WantedBy=multi-user.target

ExecStart=/usr/bin/dockerd -H fd:// —mtu=1450

이렇게 변경 후에 아래 명령 실행합니다.

$ sudo systemctl daemon-reload
$ sudo service docker restart

이제 이 전의 명령을 다시 실행해봅니다.

$ sudo docker run -it ubuntu

진행이 정상적으로 되는 것을 확인 할 수 있습니다.

Docker compose

여기까지 설치했다면 iwinv의 메뉴얼 대로 잘 설치된 상황입니다.

허나 함정이 있습니다.
바로 docker-compose를 사용하게 될 때의 문제인데요.

먼저 docker-compose를 알아봅시다.

docker compose 란 간단히 말해서 docker application을 이용한 서비스 환경 구축을 손쉽게 도와주는 tool 이라고 생각하시면 됩니다.

일반적으로 web service 구축을 위해선 web application 과 database 가 필요할 것입니다.
docker compose 는 이 둘을 한번에 구성하기 위한 툴로 보시면 됩니다.

설치방법은 아래 링크를 참고하세요.
docker-compose 설치

docker compose를 설치하고 docker-compose.yml 파일을 작성 후 docker로 서비스를 구축합니다. 여기서는 wordpress 를 구축했습니다.

docker-wordpress-nginx/docker-compose.yml at master · 9to6/docker-wordpress-nginx · GitHub

깃허브 소스를 참고하시면 됩니다.

docker-compose.yml

version: "3.2"
services:
web:
build: .
ports:
- "80:80"
volumes:
- wordpress:/var/www/html
depends_on:
- php
php:
image: wordpress:4.8-php7.1-fpm-alpine
depends_on:
- db
restart: always
ports:
- "9000:9000"
volumes:
- wordpress:/var/www/html
db:
image: mariadb:10.2.6
volumes:
- db_data:/var/lib/mysql
restart: always
ports:
- "3306:3306"

docker compose의 파일을 보면 wordpressmariadb 와 함께 설치해서 wordpress web service 를 구성하게 됩니다.

이제 wordpress 설치를 시작하게 되고 첫 화면이 뜨고 난뒤, plugin 이나 theme 를 추가하기 위해 들어가보면 목록이 나오지 않습니다.
에러가 났다고 나오고, (wp-setting.php ?? 기억이 명확하지 않네요..)의 어떤 부분에서 에러가 났다고 합니다.
이제부터 문제 해결 과정입니다.

docker compose 문제 해결 과정

extra_hosts 추가

위의 에러난 부분을 찾아가서 php 소스를 수정, echo 로 확인해봤습니다.
wordpress 내부에서 https 를 이용 api.wordpress.org 에 request 를 보내는 부분에서 계속 에러가 납니다.

구글링을 해봤더니, wordpress docker 내부에서 api.wordpress.org 의 도메인을 lookup을 못해서 일 것이라는 글을 보고 host를 추가해봤는데,

php:
image: wordpress:4.8-php7.1-fpm-alpine
depends_on:
- db
restart: always
ports:
- "9000:9000"
volumes:
- wordpress:/var/www/html
extra_hosts:
- "api.wordpress.org:66.155.40.202"

같은 증상이었습니다…

iptables 추가

전혀 해결이 되지 않아서 또다른 방법을 찾던 중 나온 방법이 iptables를 수정하는 것이 었습니다.
현재 상황이 패킷이 나가지 않는 문제라고 판단했을 때, iptables 를 이용해서 해결 할 수 있을 것이라고 판단하고 적용해봤습니다.

docker 1.10, 1.11 do not infer MTU from eth0; docker 1.9 does · Issue #22028 · moby/moby · GitHub

좋아요도 두개나 받은 내용으로 적용을 해봤는데…

실행이 되었습니다.

이렇게 해결되었다는 기쁨(?)을 느끼고 이제 마무리를 지었는데…

또다른 문제. 다시 원점으로…

제가 모바일 어플의 서버로 사용하던 rails application을 또다른 docker 파일로 실행했는데, 메일이 나가지 않는 문제를 확인했습니다. 이 rails 앱은 smtp 를 사용해서 메일을 보내는 기능이 있었는데 메일이 나가지 않아서 ruby library 파일을 직접 수정하면서 디버깅을 시작했습니다.

문제는 smtp 를 보내는 부분에서 났기 때문에 네트워크 문제로 판단, 결국 다시 원점으로 돌아갔습니다. ㅠㅠ

이렇게 또다시 하루정도 iptables 룰 도 바꿔보고 구글링도 해보고 이것저것 해보게 되었습니다.

이때쯤 iwinv 서비스 이용을 포기할 생각을 잠시 하게 되었습니다…만, 심기일전 하고 다시 구글링.

결국 찾은 해결책과 원인

마침내 찾은 해결책.
containers in docker 1.11 does not get same MTU as host · Issue #22297 · moby/moby · GitHub

docker network 를 구성할 때 mtu 설정을 별도로 해줘야한다는 것이 었습니다.

이제 뭔가 이해되는 느낌…
docker compose 로 docker application을 실행하게 되면,
docker 엔진이 별도의 sub network 를 구성하게 되고, wordpress web app 과 mariadb는 sub network 안에서 통신을 하게 됩니다.
이 때 mtu 사이즈가 1450 이상이었기 때문에 문제가 발생했던 것입니다.

해결을 위해서는
1. 첫번째로, docker-compose 안에 이렇게 network 구성을 해주는 방법이나,

networks:
default:
driver: bridge
driver_opts:
com.docker.network.driver.mtu: 1450
  1. 두번째로는, 미리 생성된 network를 이용하는 방법입니다.
$ suod docker network create -o "com.docker.network.driver.mtu"="1450"
networks:
default:
external:
name:

이 해결책을 찾아보고 다시 두번째 해결책이었던 iptables의 명령어에 대해 찾아봤는데,

TCPMSS target

Under normal circumstances, this means the size of the MTU (Maximum Transfer Unit) value, minus 40 bytes.

정상적 상황에서 MTU 사이즈에서 40바이트를 빼주는 것이라고 하네요.
아마 이래서 잘 작동했었나 봅니다. SMTP 의 패킷은 40을 빼줘도 더 1450보다 더 패킷 사이즈가 컸나 봅니다.

하지만 보다 정확한 해결책은 MTU사이즈 수정입니다.

이제 다시 SMTP 로 메일을 보내봅니다. 정상적으로 동작합니다.

결론

  • iwinvdocker 를 사용은 비추
  •  그러나 이 글을 읽어봤다면 추천;;;
  • docker 를 사용하지 않으면 손쉽게 사용가능 하니 좋은 서비스 저렴하게 사용 가능
  • docker 사용을 하시겠다면 매뉴얼의 MTU 설정과 별도 docker networkMTU 설정도 유념해야 함

서버 이전 경험 공유기 – 2. Let’s Encrypt

서버 이전 경험 공유기 – 2. Let’s Encrypt

이번에 서버이전을 하면서 이것저것 알게된 지식 및 경험을 공유하고자 이 글을 작성합니다.

이전 글은 여기서 볼수 있습니다.

Let’s Encrypt

이 전 글에서 간단히 언급했지만, Let’s Encrypt 라는 https 보급 확산을 위한, 무료 인증서 발급 프로젝트 입니다.

사실 예전부터 개인 서버에 https 를 적용하고 싶었지만, 비용이 개인이 부담하기엔 적은 금액이 아니라서 도입을 망설이고 있었습니다.
이런 찰나에 이런 프로젝트가 있다는 사실을 알게 되어 제 서버에 도입을 하지 않을 수가 없었습니다.

설치

Let’s Encrypt 를 설치하기 위해서는 Certbot 이라는 클라이언트가 필요합니다.

Install Certbot

위의 사이트를 들어가면 certbot 을 설치하는 법이 자세히 나옵니다.

간단히 정리하면,

$ wget https://dl.eff.org/certbot-auto
$ chmod a+x ./certbot-auto
$ ./certbot-auto --help

wget 으로 다운로드 받은 뒤, 실행권한 주면 끝입니다. 간단합니다.

certbot-auto 는 현재(version 0.15.0) nginxapache를 지원하고 있습니다. 만약 nginxapache 를 직접(apt-get or yum) 설치했다면 plugin 을 이용해서 연동할 수 있을 것입니다.

–apache Use the Apache plugin for authentication & installation
–standalone Run a standalone webserver for authentication
–nginx Use the Nginx plugin for authentication & installation

하지만, 저는 docker 를 이용한 관계로 그렇게 하지 못하고 다른 방식으로 설치 진행했습니다.

GitHub – 9to6/docker-nginx: Docker for nginx

githubdockerfilereadme 를 참고 하시면 되겠습니다.

핵심은 certbot 설치 후,

$ ./certbot-auto certonly --standalone --email your@email.com -d example.com -d www.example.com

위 명령 실행입니다. example.com 대신 본인의 도메인을 입력하시면 됩니다.

처음으로 실행하셨다면, 본인 이메일 입력하는 란이 나오고,
이메일을 입력 한 뒤에는,
기꺼이 본인의 이메일을 EFF(Electronic Frontier Foundation) 에 제공하겠냐고 물어보는데 저는 그냥 제공해드렸습니다. ㅎㅎㅎㅎ

Let’s Encrypt3개월 마다 한번씩 갱신해야합니다.

매번 신경 쓰기 힘드므로 crontab 에 등록해줍니다.

아래 내용은 매일 새벽 1시에 renew 를 시도하고, 성공시 nginx-simple 이라는 docker container 내부의 nginx의 설정을 다시 reload 하라는 뜻 입니다.

$ sudo echo "0 1 * * * /home/user/certbot-auto renew --quiet --renew-hook \"/usr/bin/docker exec nginx-simple nginx -s reload\"" | sudo tee -a /var/spool/cron/crontabs/root

결론

https 설치가 무사히 완료되었습니다.
이제 appstore application 의 adhoc 버전 배포할 때 굳이 dropbox를 써야하는 번거로움도 사라지겠네요. (다만 요즘 앱개발 할 일이 전혀 없습니다…)

https 적용으로 보안성도 강화되었습니다.
SSL Server Test (Powered by Qualys SSL Labs) 기념으로 이곳에서 보안성 테스트도 해줬습니다.
점수가 괜찮은 듯 합니다.

만족스럽습니다. 여러분들도 https 적용하시고 https 의 빠른 보급에 작은 기여를 해주셨으면 합니다.

서버 이전 경험 공유기 – 1. Dockerizing

이번에 서버이전을 하면서 이것저것 알게된 지식 및 경험을 공유하고자 이 글을 작성합니다.

서버 이전

서버 이전을 하게 되었습니다.
기존엔 cloudv 를 쓰고 있었는데, 같은 회사에서 나온 iwinv 가 한국형 AWS가 되겠다고 하고 과감하게 출사표를 던저서 가격을 보던 중, iwinv 가 압도적으로 좋다고 판단해서 서버이전을 마음먹었습니다.

기존 cloudv 사양

1core, 3G memory, 100G ssd -> 월 31900원

이전 iwinv 사양

2core, 6G memory, 25G ssd -> 월 20900원

iwinv 는 블록스토리지 20g 추가 당 2000원.

굳이 이전하지 않을 이유가 없었습니다.

아무튼…

이전하는 김에 제 개인 서버를 모두 Dockerizing 하기로 마음을 먹고, 작업을 진행하던 중에, 요즘 무료로 https 를 발급해주는 Let’s Encrypt 라는 프로젝트가 있다는 사실을 알게 되었습니다.

그래서 이것도한 시도를 하겠다는 마음을 덜컥 먹어버린…

이런 이유로 시작한 설치 경험을 공유합니다.

Docker

소개

Docker 는 요즘 모르는 사람이 별로 없을 것 같습니다만, 상세소개는 페이지 링크로 대체합니다.

Official Site Overview
nacyot의 프로그래밍 이야기 :: 도커(Docker) 튜토리얼 : 깐 김에 배포까지

간단히 Docker 에 대해 설명하자면 아래 아키택트 이미지로 쉽게 표현이 가능할 것이라고 생각합니다.

Docker Architecture vs Virtual machine

Docker 를 이해하기 위해선 가상 머신(Virtual machine)과의 비교는 필수라고 생각합니다.

한마디로 제게 Docker 를 표현하라고 한다면, Virtual machine 의 장점(isolation, distribution)을 취했으나, 훨씬 더 비용이 적게드는 시스템이 아닐까합니다.

Docker 를 적용하는 이유

이런 도커를 이용해서 제 블로그 및 서버를 구성하기로 마음먹은 겁니다.

이유는 여러가지가 있지만 가장 큰 이유는, 개인서버는 형편상 이사갈 일이 많습니다.
좀 더 저렴하고 좋은 서비스가 나오면 이사를 가야하기 때문이죠.
적고보니 회사든 개인이든 비용문제는 같은 거군요..

Docker를 적용한다면 앞으로 다른 더 좋은 호스팅 서비스가 나올 경우, 쉽게 갈아탈 수 있게 하기 위함입니다. 도커 이미지만 Download 받고 실행하면 그만이거든요.

Dockerizing 본격 시작

이 블로그는 블로그계의 원탑 wordpress 로 이뤄져있고, 워드프레스는 역시 유명한 만큼 자료가 많더군요.

Quickstart: Compose and WordPress

Docker 공식 사이트에 이렇게 docker compose 로 결합하는게 나옵니다.

하지만 부족합니다…
이유는 저는 일단 mysql 을 사용하지 싫고, mariadb를 사용하고 싶기 때문이며,
하나는 역시나 이것또한 비용 문제로 docker image size 를 조금이라도 줄이고 싶기 때문입니다.

그러기에 저는 Alpine Linux 를 쓸 생각을 하게 됩니다.

Using docker compose

GitHub – 9to6/docker-wordpress-nginx: Docker compose for WordPress

docker compose 를 이용해서 워드프래스를 구성하실 분은 위 링크를 참고하시면 좋을 듯합니다.

구성은,

nginx 1.13 alpine, mariadb 10.2.6, wordpress 4.8 alpine

으로 구성했으며, wordpress Plugin인 duplicator 의 손쉬운 사용을 위해, 기본 Dockerfile에서 zip 라이브러리를 추가했습니다.

Using only Dockerfile

심플하기는 위에 것보다 아래 링크가 더 심플합니다.
GitHub – 9to6/docker-wordpress: docker + nginx + mariadb + supervisor + php7

이건 docker compose 를 사용하지 않고, 하나의 도커파일에 nginx + mariadb + wordpress + supervisor 를 한번에 담은 것으로 단순 wordpress 를 호스팅하길 원하시는 분은 이것이 훨씬 단순할 것입니다.

$ sudo docker pull 9to5/wordpress

Docker hub 에 이미지도 올려놓았으니 필요한 분들은 사용하시면 됩니다.

결론

이렇게 해서 도커를 이용해서 워드프레스 서버 구성을 끝냈습니다.
여러분이 보고 있는 이 화면이 결과물입니다.

다음 글은 wordpress 블로그에 무료 https 적용하는 방법을 기술하겠습니다.

[AWS] Amazon web service 의 서비스 간단 정리

AWS 서비스 정리

AWS를 공부해야겠다고 마음먹고 AWS를 막상 시작하려고 하면,
그 방대한 사이즈에 지래 겁을 먹게 됩니다.
또한 AWS의 어떤 특정 기능에 대해 찾아보려고 하면 또다른 AWS서비스들이 연계되어서 다시 리서치를 해야하는 번거로움에 빠지게 됩니다.

이에 저의 고생을 경험삼아 다른분들의 고생을 미리 방지하고자 사람들을 위해 AWS 서비스를 간단하게 정리했습니다.

EC2(Amazon Elastic Compute Cloud)

VM기반의 컴퓨팅 자원을 제공하는 서비스
일반적인 클라우드 서버 인스턴스를 의미

Instance Family Current Generation Instance Types
General purpose t2.nano, t2.micro, t2.small, t2.medium, t2.large, t2.xlarge, t2.2xlarge, m4.large, m4.xlarge, m4.2xlarge, m4.4xlarge, m4.10xlarge, m4.16xlarge, m3.medium, m3.large, m3.xlarge, m3.2xlarge
Compute optimized c4.large, c4.xlarge, c4.2xlarge, c4.4xlarge, c4.8xlarge, c3.large, c3.xlarge, c3.2xlarge, c3.4xlarge, c3.8xlarge
Memory optimized r3.large, r3.xlarge, r3.2xlarge, r3.4xlarge, r3.8xlarge, r4.large, r4.xlarge, r4.2xlarge, r4.4xlarge, r4.8xlarge, r4.16xlarge, x1.16xlarge, x1.32xlarge
Storage optimized d2.xlarge, d2.2xlarge, d2.4xlarge, d2.8xlarge, i2.xlarge, i2.2xlarge, i2.4xlarge, i2.8xlarge, i3.large, i3.xlarge, i3.2xlarge, i3.4xlarge, i3.8xlarge, i3.16xlarge
Accelerated computing p2.xlarge, p2.8xlarge, p2.16xlarge, g2.2xlarge, g2.8xlarge
  1. T2는 웹서버, 데이터 베이스에 사용하기 좋음, 순간 확장용으로 적합
  2. M3는 SSD 스토리지 사용
  3. C4는 CPU를 많이 쓰는 서비스에 적합 -> ssd도 필요하면 C3
  4. X1, R3은 메모리가 많이 필요한 서비스에 적합(빅데이터 치리 엔진, Apache Spark, Presto)
  5. P2, G2는 GPU 계산에 특화 (머신러닝)
  6. I3는 스토리지에 최적화 (높은 I/O가 필요한 작업)

EBS(Elastic Block Store)

EC2 인스턴스에 사용할 영구 블록 스토리지 볼륨을 제공
Amazon EBS 볼륨은 워크로드 실행에 필요한 지연 시간이 짧고 일관된 성능을 제공 -> S3와의 큰 차이점

그러나 S3에 비해 비쌈

EIP(Elastic IP)

EC2인스턴스를 생성하고 주는 IP는 고정IP가 아닌 유동IP
인스턴스를 재시작하면 IP가 변경됨
고정아이피 서비스 -> EIP

ELB(Elastic Load Balancing)

EC2를 대상으로한 요청을 여러대의 EC2 인스턴스로 자동으로 분배해주는 기능
이전엔 L4/L7 로드 밸런서를 이용하던 기능을 간단한 WEB UI로 손쉽게 이용가능

로드 밸런서는 EC2의 작동 상태를 확인하여 정상적으로 작동하고 있는 인스턴스만을 대상으로 요청을 분배함

Sticky Session을 이용하면 로드밸런싱을 해줄 때 사용자의 쿠키 세션을 이용해여 요청 분배작업을 수행, 초기 접속 인스턴스로 연결 시켜줌

Key Pairs

AWS ssh접속public/private 키를 이용하여 접속
각각의 key pair에는 이름이 필요하고, 이름은 publickey와 연결됨

Security Group

EC2에서 일종의 방화벽 처럼 사용됨
inbound/outbound traffic에 대해 port별로 접근 제어할 수 있는 기능 제공
호스팅 환경에서 DMZ와 같은 개념 구현 가능

S3 (Simple Storage Service)

웹 인터페이스를 통해 데이터를 저장 및 검색할 수 있는 스토리지
RRS(Reduced Redundancy Storage) 옵션으로 데이터 손실 위험도를 더 올리고 가격을 저렴하게 사용가능

Bucket

데이터를 저장하기 위한 Amazon S3의 기본 컨테이너
버킷에 데이터를 무한정으로 저장 가능

Snapshot

EBS 볼륨 전체의 내용 중 특정 시점을 파일로 저장한 형태 (EBS 볼륨 백업)

VPC(Virtual Private Cloud)

AWS에서 가상사설망을 만들어줄수 있게 해주는 서비스
이 서비스 전에는 EIP이외에는 정적 서비스를 사용할 수 없었음(ex> 10.x.x.x같은 사설 ip 사용하지 못했으나, VPC를 통해 가능해짐)

Lambda

서버없이 특정 이벤트 발생시 코드 실행을 시켜주고, 이에 대한 비용만을 지불하는 AWS의 서비스
런타임으로 Java, nodejs, python, C# 사용가능

Blue Print라는 코드 템플릿을 선택해서 사용가능하다

Route 53

AWS의 Domain Name Service 이다.
ELB(로드 밸런서)를 사용할 때 함께 사용하는 서비스

라우팅 정책

  1. 단순 라우팅
    하나의 인스턴스 사용
  2. 가중치 기반 라우팅
    다수의 리소스를 하나의 DNS와 연동 가능하나, 각 리소스에 가중치 부여 가능

    리소스 3개 -> 가중치 1,1,3 부여했을 경우
    DNS요청시 1로 설정된 리소스는 5번중 한번, 3으로 설정된 리소스는 5번중 3번 반환

  3. 지연 시간 라우팅
    지연시간이 가장 낮은 인스턴스 선택

  4. 지리적 라우팅
    사용자의 지역에 따라 인스턴스 선택 -> Localization 가능

ElastiCache

클라우드에서 In Memory Data Store로 사용 하거나, 캐시를 손쉽게 배포, 운영, 확장할 수 있게 해주는 웹서비스

  1. Redis
    RedisElastiCache는 확장 가능(최대 15개의 샤드 클러스터 지원 3.55TiB)
  2. Memcached
    ElastiCacheMemcached와 프로토콜 호환. 기존 환경에서 사용하는 도구를 손쉽게 사용 가능

CloudFront

AWS에서 제공하는 CDN서비스
이미지, 오디오, 비디오 및 일반 웹 페이지 등을 최종 사용자에게 빠르게 제공
에지 로케이션(Edge Location)이라는 일종의 캐시서버를 이용하여 지연시간 단축

IAM(Identity and Access Management)

AWS 계정의 암호나 액세스 키 공유없이 다른 계정에 권한 부여 가능

  1. 리소스에 따른 계정 권한
  2. 읽기 쓰기 권한 등.. -> 차등 권한 부여 가능

사용자

AWS의 서비스 계정으로 간주하면 됨

윈도우즈를 사용할 때 여러 계정을 만들 수 있는 것과 같은 이치

ARN(Amazon Resource Name)

아래 형태로 사용

arn:aws:iam::account-ID-without-hyphens:user/Bob

그룹

IAM사용자들의 집합체
but 리눅스의 group개념과는 다른 그냥 여러 사용자들에게 한번에 정책을 연결하는 수단일 뿐

역할

사용자와 유사
_but 역할은 한 사람과만 연관되지 않고 그 **역할이 필요한 사람이면 누구든지 맡을 수 있도록 고안**_

CodeCommit

프라이빗 Git 리포지토리를 손쉽게 운영할 수 있는 서비스
가격이 싸다

SNS(Simple Notification Service)

푸시 알림 서비스로서, 개별 메시지를 전송하거나 대규모의 수신자에게 메시지를 전송 가능
Baidu Cloud Push를 통해 Android, Apple, Google, Fire OS, Windows 디바이스에도 알림 전송 가능
Amazon Simple Queue Service(SQS), AWS Lambda 함수 또는 모든 HTTP 엔드포인트에도 메시지를 전송 가능

토픽(Topic)

여러 개의 엔드포인트를 그룹으로 만든 것. 토픽을 구독한 모든 엔드포인트로 알림 전송

SQS(Simple Queue Service)

메시지를 저장하는 대기열에 대한 액세스를 제공하는 웹 서비스

메시지 큐

대기열 유형

  1. 표준 대기열
    기본 대기열, 메시지가 1개 이상 전달될 수 있으며 순서 또한 바뀔 수 있음
    무제한의 초당 트랜잭션 수 제공
  2. FIFO 대기열
    순서 및 메시지 단일 전달 보장
    초당 트랜잭션 수가 300개 제한

CloudWatch

AWS 클라우드 리소스와 AWS에서 실행되는 애플리케이션을 위한 모니터링 서비스
자동으로 EC2 인스턴스를 모니터링
1. Auto Scaling Group
2. Elastic Load Balancer
3. Route 53

메트릭(Metric)

AWS 시스템의 퍼포먼스에 관한 데이터들을 뜻함

기본적으로 제공하는 CloudWatch의 모니터링 기능은 이 메트릭을 이용해서 보여진다(EC2, ELB등의 기본 서비스 관련 정보등..)
사용자가 커스텀 메트릭 생성가능

상태는 3가지

  1. OK
    정의된 임계치 안, 현재 정상
  2. Alarm
    정의된 임계치 상회, 비정상
  3. Insufficient
    데이터 불충분으로 상태 판독 불가

Auto Scaling

Auto Scaling이란?

EC2 인스턴스를 자동으로 생성하고 삭제해주는 서비스

Launch Configuration

Auto Scaling을 할 때 사용하는 설정값

어떤 이미지(AMI)를 어떤 인스턴스 타입(EC2)으로 스토리지(EBS) 및 보안설정(SG)과 함께 사용할 것인가를 선택

ex> Linux AMI 이미지를 t2.micro로 EBS 20G와 함께 port 80번만을 열어서 실행한다.

AutoScaling Groups

위의 설정값을 사용해서 실제 Auto Scaling을 수행하기 위한 Grouping

어떤 설정값으로, 어떤 네트워크에, 어떤 정책(인스턴스를 추가하고 제거하는 방법 등의 정책)을 이용해서 오토 스케일링을 할 것 인가에 대한 설정

ex> ASG을 통해서 생성된 EC2 인스턴스들의 CPU 점유율이 평균 80%가 5분동안 넘을 때 EC2 인스턴스를 현재의 2배씩 증가 시킨다

OpsWorks

서버 구성을 자동화 플랫폼 Chef를 사용해서 하는 관리 서비스
어플리케이션과 서버 관리를 용의하게 해줌

  1. OpsWorks Stacks
  2. AWS OpsWorks for Chef Automate

OpsWorks Stacks

OpsWorks 개념도

위의 개념도를 참고.

Stack > Layer > Instance > App

Stack

스택은 OpsWorks에서 최상위 단위
스택안에 여러 개의 레이어가 포함가능함

Layer

EC2 인스턴스 생성을 위한 틀(탬플릿의 개념)
OpsWorks 내장으로 Rails with Passenger, Java with Tomcat, Nodejs, RDS 등을 기본으로 지원하고, Custom하게 만들 수도 있음

내장 탬플릿으로 레이어를 생성하면 AWS에서 지원하는 Chef 레시피(Recipe)들이 기본적으로 들어가있다.(Chef 12의 경우는 없다고 하는데 실행해보지는 않음)

Opsworks Lifecycle Events

Layer들은 5개의 이벤트를 가지고 있음, 이벤트 발생시 각 이벤트마다 등록된 레시피(Recipe)가 실행됨

  1. Setup
    인스턴스 부팅이 완료된 후 발생
    수동으로 이벤트 발생 가능
    명렁 참고

  2. Configure
    스택의 모든 인스턴스들 중 어느 하나라도 아래 상황 중 하나의 경우에 해당할 경우, 모든 인스턴스에게 발생함

    • 인스턴스가 온라인 상태가 되었거나, 온라인 상태에서 벗어날때(leave the online)
    • 인스턴스가 EIP가 할당되거나, 할당이 취소될 때
    • ELB를 레이어에 연결하거나, 연결해제 할때
  3. Deploy
    Deploy Command를 실행했을 때 발생
    Setup이 완료된 후에 Deploy 레시피가 실행됨

  4. Undeploy
    앱을 지웠거나 Undeploy 명령을 실행 했을 때 발생

  5. Shutdown
    Opsworks에서 인스턴스를 종료하고, 실제로 EC2인스턴스가 종료하기전에 발생
    인스턴스를 리부팅할때는 어떤 이벤트도 발생하지 않음

AWS OpsWorks for Chef Automate

Chef Automate를 AWS에서 손쉽게 이용할 수 있는 서비스
현재(2017년 5월) US East (Northern Virginia), US West (Oregon) 및 Europe (Ireland) 지역에서만 이용 가능

Habitat(앱 빌드 및 패키징 자동화), InSpec(컴플라이언스 자동화)과 Chef를 함께 사용하는 CI(지속적 통합)서비스

Chef Automate AWS 블로그

KMS (Key Management Service)

데이터를 암호화할 때 사용하는 암호화 키를 쉽게 생성하고 제어할 수 있게 해주는 관리형 서비스

AWS product category AWS services integrated with KMS
Compute Amazon Lightsail*, Amazon EC2 SSM*, AWS Lambda
Storage & Content Delivery Amazon S3, Amazon EBS, AWS Import/Export Snowball, AWS Storage Gateway
Databases Amazon RDS, Amazon Redshift, AWS Database Migration Service
Developer Tools AWS CodeCommit*
Management Tools AWS CloudTrail
Analytics Amazon EMR, Amazon Kinesis Firehose
Application Services Amazon Elastic Transcoder, Amazon SES
Enterprise Applications Amazon WorkSpaces, Amazon WorkMail

KMS는 AWS SDK, the AWS Command Line Interface, RESTful API와 통합해서 사용

CloudTrail

  • CLoudTrail은 AWS 계정 사용에 대한 관리, 운영 감사, 취약점 감사등을 도와주는 서비스
  • AWS상의 서비스에 대한 로그, 지속적 모니터링, api사용 관련 이벤트등 제공

결론

AWS에는 훨씬 더 많은 서비스들이 존재하고 앞으로도 계속 생길 것입니다.
이번 AWS Summit 2017 in Seoul 도 참여 했었는데 새로운 서비스들이 등장하더군요.

AWS 자격증도 있던데 2년마다 갱신되고 상당히 힘들어보였습니다.
관심있으시면 한번 도전해보세요.

[adsense2]

ubuntu 14.04(trusty)에 docker install

Ubuntu 우분투 14.04 docker 설치

$ sudo apt-get update
$ sudo apt-get install -y docker-engine

을 하면 에러가 나고 아래와 같은 메시지를 만나게 됩니다.

Reading package lists... Done
Building dependency tree
Reading state information... Done
docker-engine is already the newest version.
You might want to run 'apt-get -f install' to correct these:
The following packages have unmet dependencies:
docker-engine : Depends: libsystemd-journal0 (>= 201) but it is not going to be installed
Recommends: aufs-tools but it is not going to be installed
Recommends: cgroupfs-mount but it is not installable or
cgroup-lite but it is not going to be installed
Recommends: git but it is not going to be installed
E: Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution).

보면 dockerlibsystemd-journal0에 의존성이 걸려있어서 그런데요.
설치가 안되는 이유는 잘 모르겠으나, 그냥 수동으로 설치해줬습니다.

파일을 찾아보다가 나중에 또 이런일이 생길 듯하여 기록에 남겨둡니다.

$ wget http://kr.archive.ubuntu.com/ubuntu/pool/main/s/systemd/libsystemd-journal0_204-5ubuntu20_amd64.deb

위 명령으로 *.deb 파일을 다운로드 받은 뒤에 수동 설치합니다.

$ sudo dpkg -I libsystemd-journal0_204-5ubuntu20_amd64.deb

설치 후 다시 docker install 을 시도합니다.

$ sudo apt-get install -y docker-engine

정상 설치가 되었습니다.

Reading package lists... Done
Building dependency tree
Reading state information... Done
docker-engine is already the newest version.
0 upgraded, 0 newly installed, 0 to remove and 29 not upgraded.
1 not fully installed or removed.
After this operation, 0 B of additional disk space will be used.
Setting up docker-engine (17.05.0~ce~rc3-0~ubuntu-trusty) ...
docker start/running, process 3434
Processing triggers for ureadahead (0.100.0-16) ...

설치가 잘 되었는지 확인합니다.

$ docker

정상 설치되었다면 usage가 나옵니다.

잘 설치되었다면 이제 docker를 잘 이용하시면 됩니다.

Error occurs when start an instance AWS OpsWorks

Error occurs when start an instance AWS OpsWorks

When I start a new instance on OpsWorks Layers, I faced this error.

================================================================================
Recipe Compile Error in /var/lib/aws/opsworks/cache.stage2/cookbooks/aws/resources/cloudwatch.rb
================================================================================

NoMethodError
-------------
undefined method `property' for #&lt;Class:0x007f511b6ee538&gt;

Cookbook Trace:
---------------
/var/lib/aws/opsworks/cache.stage2/cookbooks/aws/resources/cloudwatch.rb:1:in `class_from_file'

Relevant File Content:
----------------------
/var/lib/aws/opsworks/cache.stage2/cookbooks/aws/resources/cloudwatch.rb:

1&gt;&gt; property :alarm_name, String, name_property: true
2: property :alarm_description, String
3: property :actions_enabled, TrueClass
4: property :ok_actions, Array, default: []
5: property :alarm_actions, Array, default: []
6: property :insufficient_data_actions, Array, default: []
7: property :metric_name, String
8: property :namespace, String
9: property :statistic, equal_to: %w(SampleCount Average Sum Minimum Maximum)
10: property :extended_statistic, String

I got a panic….
Because it certainly worked fine when I start an instance before a couple of hours…

I had found a solution.
Finally I found it.

That’s why AWS cookbook updated.

My OpsWorks system used chef11.
When AWS cookbook updated 6.1.0, it has used new method, property.

I specified a version of AWS cookbook on my Berkshelf

Finally it works well.

p80.pool.sks-keyservers.net: Host not found

AWS의 Opsworks에서 새로운 instances를 만들다가 만난 에러를 정리해둡니다.

AWS의 Opsworks 는 인스턴스를 새로 생성하면 등록되어있는 Chef Recipe 들을 자동으로 실행해주는 툴입니다.

이번에 Instance 한개를 추가로 생성하고, 그 Instance에 하나의 App 을 배포하려고 기존 Layer에서 추가로 Instance 를 생성하게 되었습니다.

그런데 갑자기 에러가 발생해서 로그를 봤더니 이런 로그가 있었습니다.

Mixlib::ShellOut::ShellCommandFailed
------------------------------------
execute[install-key 58118E89F3A912897C070ADBF76221572C52609D] (/var/lib/aws/opsworks/cache.stage2/cookbooks/apt/providers/repository.rb line 28) had an error: Mixlib::ShellOut::ShellCommandFailed: Expected process to exit with [0], but received '2'
---- Begin output of apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv 58118E89F3A912897C070ADBF76221572C52609D ----
STDOUT: Executing: gpg --ignore-time-conflict --no-options --no-default-keyring --homedir /tmp/tmp.YjqEGDmda9 --no-auto-check-trustdb --trust-model always --keyring /etc/apt/trusted.gpg --primary-keyring /etc/apt/trusted.gpg --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv 58118E89F3A912897C070ADBF76221572C52609D
?: p80.pool.sks-keyservers.net: Host not found
gpgkeys: HTTP fetch error 7: couldn't connect: Success
STDERR: gpg: requesting key 2C52609D from hkp server p80.pool.sks-keyservers.net
gpg: no valid OpenPGP data found.
gpg: Total number processed: 0
---- End output of apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv 58118E89F3A912897C070ADBF76221572C52609D ----
Ran apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv 58118E89F3A912897C070ADBF76221572C52609D returned 2

Resource Declaration:
---------------------
# In /var/lib/aws/opsworks/cache.stage2/cookbooks/ops-docker/recipes/install.rb

4: apt_repository 'docker' do
5: uri node['docker']['package']['repo_url']
6: distribution node['docker']['package']['distribution']
7: components ['main']
8: keyserver node['docker']['package']['repo_keyserver']
9: key node['docker']['package']['repo_key']
10: end
11:

Compiled Resource:
------------------
# Declared in /var/lib/aws/opsworks/cache.stage2/cookbooks/ops-docker/recipes/install.rb:4:in `from_file'

apt_repository("docker") do
action :add
retries 0
retry_delay 2
cookbook_name "ops-docker"
recipe_name "install"
uri "https://apt.dockerproject.org/repo"
distribution "ubuntu-trusty"
components ["main"]
keyserver "hkp://p80.pool.sks-keyservers.net:80"
key "58118E89F3A912897C070ADBF76221572C52609D"
cache_rebuild true
end

[2017-05-03T09:17:52+00:00] INFO: Running queued delayed notifications before re-raising exception
[2017-05-03T09:17:52+00:00] ERROR: Running exception handlers
[2017-05-03T09:17:52+00:00] ERROR: Exception handlers complete
[2017-05-03T09:17:52+00:00] FATAL: Stacktrace dumped to /var/lib/aws/opsworks/cache.stage2/chef-stacktrace.out
[2017-05-03T09:17:52+00:00] ERROR: apt_repository[docker] (ops-docker::install line 4) had an error: Mixlib::ShellOut::ShellCommandFailed: execute[install-key 58118E89F3A912897C070ADBF76221572C52609D] (/var/lib/aws/opsworks/cache.stage2/cookbooks/apt/providers/repository.rb line 28) had an error: Mixlib::ShellOut::ShellCommandFailed: Expected process to exit with [0], but received '2'
---- Begin output of apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv 58118E89F3A912897C070ADBF76221572C52609D ----
STDOUT: Executing: gpg --ignore-time-conflict --no-options --no-default-keyring --homedir /tmp/tmp.YjqEGDmda9 --no-auto-check-trustdb --trust-model always --keyring /etc/apt/trusted.gpg --primary-keyring /etc/apt/trusted.gpg --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv 58118E89F3A912897C070ADBF76221572C52609D
?: p80.pool.sks-keyservers.net: Host not found
gpgkeys: HTTP fetch error 7: couldn't connect: Success
STDERR: gpg: requesting key 2C52609D from hkp server p80.pool.sks-keyservers.net
gpg: no valid OpenPGP data found.
gpg: Total number processed: 0
---- End output of apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv 58118E89F3A912897C070ADBF76221572C52609D ----
Ran apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv 58118E89F3A912897C070ADBF76221572C52609D returned 2
[2017-05-03T09:17:53+00:00] FATAL: Chef::Exceptions::ChildConvergeError: Chef run process exited unsuccessfully (exit code 1)

해서 검색을 시작했습니다.
저는 OpsWorksDocker에 서툴러서 뭔 실수를 했나 싶었는데 결과는…
그냥 단순히 서버 다운… OTL.

p80.pool.sks-keyservers.net: Host not found
gpgkeys: HTTP fetch error 7: couldn’t connect: Success

그냥 저 서버가 죽은거 였네요.

저 서버가 Docker설치시 기본으로 바로보는 PGP key server인 듯..
아래 링크가 이 에러와 관련된 Thread입니다.

Key server down for get.docker.com · Issue #13555 · moby/moby · GitHub

여기 가보면 kris라는 사람이
기존 Docker가 사용하는 서버주소를
From,

p80.pool.sks-keyservers.net

To,

hkp://keyserver.ubuntu.com:80

로 변경해주라고 답을 달아놨더군요.

 

결론

아무튼 이 버그의 결론은,
잠시뒤에 다시 시도 해본다;;;;

서버가 살아날 시간을 주는 것입니다;;

[git] git add 취소하는 방법

git 명령어

 

 

git를 사용하면서 잊어버리는 명령들을 하나씩 기록해두고자 작성합니다.

 

“`git status“`

 

해서 원하는 파일을 찾고,

“`git rm –cached“`

 

으로 staging area에 있는 파일을 지울 수 있습니다.

물론 실제 파일은 지워지지 않습니다.

[golang] Go언어 시작하기 – 배열(array)과 슬라이스(slice)

배열(array)슬라이스(slice)

Go언어에 배열과 슬라이스에 대해 알아보겠습니다.
Go언어는 많은 객체 지향 언어에서 기본으로 지원하는 list타입이 없고, 배열과 슬라이스가 존재합니다.
배열을 선언하는 법은 먼저 배열의 길이를 선언하고, 타입(type) 뒤에 초기화 할 값을 넣어줍니다.

배열 선언

array := [5]int{1,2,3,4,5}
array := […]int{1,2,3}

위의 형태로 사용합니다.
Go언어는 일반적으로 알고 있는 (C, Java와 같은) 언어들과 type declaration Syntex가 반대입니다.

golang의 syntex에 대한 설명은 아래 링크를 참고하시면 됩니다.
golang syntex에 대해

위의 배열 선언 코드를 보면 익숙하지 않는 연산자가 나옵니다.

:-

위의 연산자는 변수의 선언과 할당을 동시에 할때 사용하는 연산자로 Go언어에서 자주 쓰입니다.
앞으로 Go언어에 대한 코드를 볼때 자주 접하게 될겁니다.

슬라이스 선언

slice := []int

slice는 동적 배열의 개념으로 만들어진 것으로 빠르고 효과적으로 배열의 크기를 늘리거나 줄일 수 있습니다.
append라는 내장 함수를 이용해서 데이터를 추가 할 수 있으며, 아래 보이는 형태를 이용해서 slice를 쉽게 잘라낼 수도 있습니다.

slice := []int{1,2,3,4}
newSlice := append(slice, 5) // newSlice는 [1,2,3,4,5]
newSlice2 := slice[1:2] // newSlice2는 [2,3]

위의 두 가지를 보면 배열과 슬라이스의 차이를 명확하게 알수 있습니다.
배열은 사이즈를 정확히 지정해야하고, 슬라이스는 사이즈를 지정할 필요가 없습니다.
즉, 사이즈를 지정하면 배열로 선언이 되고, 사이즈를 지정하지 않는다면 슬라이스로 선언이 되는 것입니다.

슬라이스(slice)의 특징

슬라이스의 특징을 알아보기 위해 슬라이스의 주소값을 출력하는 샘플코드 입니다.

package main

import (
"fmt"
)

func testArray(array [5]int) {
fmt.Printf("in testArray() func %p\n", &array)
}

func testSlice(slice []int) []int {
fmt.Printf("in testSlice() func %p\n", slice)
return append(slice, 6)
}

func main() {
array := [5]int{1, 2, 3, 4, 5}
fmt.Printf("origin ptr: %p\n", &array)
testArray(array)

// 배열을 슬라이스로 변환, 메모리 주소는 현재까지 동일함
slice := array[:]
fmt.Printf("%v, %p\n", slice, slice)

slice2 := testSlice(slice)
// 메모리가 변함. 새로 할당 한 듯
fmt.Printf("%v, %p\n", slice2, slice2)

// 이후부터는 같음
slice2 = append(slice2, 7)
fmt.Printf("%v, %p\n", slice2, slice2)

}

처음 배열을 선언하고 메모리 주소를 확인하고, 이후 슬라이스로 변환하고, 슬라이스의 데이터를 변환하면서 주소를 확인해 가는 코드입니다.
output

origin ptr: 0xc420012180
in testArray() func 0xc4200121b0
[1 2 3 4 5], 0xc420012180
in testSlice() func 0xc420012180
[1 2 3 4 5 6], 0xc420016140
[1 2 3 4 5 6 7], 0xc420016140

실행결과는 위와 같습니다.
간단히 해석하자면,

origin ptr: 0xc420012180
in testArray() func 0xc4200121b0

함수 실행시 넘긴 배열인자의 주소를 확인한 결과 주소가 변했습니다.
이 경우는 callbyvalue로 함수를 호출하게 되어 배열를 deep copy하므로 주소가 변한 것입니다.
배열과 슬라이스의 callbyvalue, callbyreference에 대한 내용은 아래에서 다른 예제코드로 보도록 하겠습니다.

[1 2 3 4 5], 0xc420012180
in testSlice() func 0xc420012180

슬라이스로 변환한 결과 배열과 주소는 동일합니다.
이 경우는 결국 타입만 변경된 것입니다.
실제 주소는 같습니다. 결국 내부 데이터를 array에서 바꾼다고 하면, slice의 값도 변할 것입니다.

[1 2 3 4 5 6], 0xc420016140
[1 2 3 4 5 6 7], 0xc420016140

여기서 부터 재미있습니다.
testSlice(...) 함수를 호출했을 때 내부에서 append라는 내장 함수를 호출합니다.

append는 slice에 값을 추가할 때 사용하는 내장함수로 len, cap등과 함께 자주 접하게 될 것입니다.

append함수를 호출하고 return을 하게 되면 새로운 slice가 반환하게 됩니다.

[1 2 3 4 5 6], 0xc420016140

보면 주소가 변경 되었다는 것을 알수 있습니다.
그런데!!, 두번째 append호출했을 때는 주소가 그대로 인 것을 알 수 있습니다.

[1 2 3 4 5 6 7], 0xc420016140

slice는 기본적으로 lengthcapacity를 가지고 있는데, 이것에 대한 상세한 설명은 두개의 링크로 대신합니다.

Go Slices: usage and internals
Arrays, slices (and strings): The mechanics of ‘append’

배열(array)과 슬라이스(slice)의 차이점

  • Call by value
  • Call by reference

둘의 가장 큰 차이점입니다.
배열은 인자(argument)로 받을 경우 callbyvalue로,
슬라이스는 callbyreference로 받게 됩니다.

이 것을 눈으로 확인해보기 위해 간단한 샘플코드를 만들었습니다.

func testArray(array [1e7]int)
* 천만개의 배열을 복사

func testSlice(slice []int)
* 포인터만 복사
callbyvaluecallbyreferrence를 단순비교하기 위해서는
위의 샘플코드처럼 배열과 슬라이스의 주소를 확인하기면 하면 되지만,
배열과 슬라이스를 함수에서 사용할 때 둘 사이의 차이를 쉽게 느껴보고자 아래 코드를 만들었습니다.

package main

import (
"fmt"
"time"
)

func callByValue(array [1e7]int) int64 {
return time.Now().UnixNano() / int64(time.Millisecond)
}

func callByReference(slice []int) int64 {
return time.Now().UnixNano() / int64(time.Millisecond)
}

func main() {
array := [1e7]int{}

t := time.Now().UnixNano() / int64(time.Millisecond)
t2 := callByValue(array)
fmt.Printf("call by value elapsed time : %f\n", float32(t2-t)/1000)

t = time.Now().UnixNano() / int64(time.Millisecond)
slice := array[:]
t3 := callByReference(slice)
fmt.Printf("call by reference elapsed time : %f\n", float32(t3-t)/1000)

}

output

call by value elapsed time : 0.043000
call by reference elapsed time : 0.000000

큰 배열을 인자로 넘겨야하는 경우, 배열은 전체복사가 된다는 점을 알고 있어야 합니다.


여기까지가 배열과 슬라이스에 대한 간단한 정리였습니다.

 [golang] Go언어 시작하기(Overview) – 1

 

Go 언어(golang) 시작하기

최근, 회사에서 Go언어를 쓰게 되어서 간단하게 Go언어에 대해서 간단하게 포스팅 해보려합니다.

저도 많은 내용을 아는 것은 아니니 부족한 부분이 많을 것입니다.

이 글은 정리차원에서 적어두는 것이나, Go언어를 잘 모르시는 분, Go언어에 관심이 가는 분, 또는 Go언어를 배워보고 싶은 분들께 유익한 글이 되었으면 합니다.

Let’s Go

새로운 언어를 배울 때 가장 먼저 확인하는 hello world 입니다.
Go 놀이터에 가셔서 확인하실 수 있고, 웹상에서 테스트도 가능합니다.

package main

import (
"fmt"
)

func main() {
fmt.Println("Hello, playground")
}

위의 코드를 보면 Java처럼 현재 파일의 패키지를 설정하고 있고
import 로 사용할 패키지를 지정, main 함수가 기본 프로그램 엔트리 포인트입니다.
특이한 것이 main함수에 인자가 없습니다.
인자(ARGV)를 받기위해서는 os package를 import 해야합니다.

Go 언어 넌 누구니?

1. 컴파일 기반의 정적 타입 언어 (compiled language)

Go언어는 컴파일 기반의 정적 타입언어입니다.
이는 컴파일로 인해 파이썬(Python)이나 루비(Ruby)같은 인터프리터(interpreter) 언어로 개발할 때보다 버그 요소가 많이 줄어듬을 의미합니다.
물론 컴파일언어의 특징인 빠른 속도 또한 당연합니다.
특히 Go언어의 컴파일러는 C언어에서의 warning (예를 들면, 사용하지 않는 변수나 패키지를 import했을시에 Go 컴파일러는 오류를 발생시킵니다.) 에 해당하는 문제들도 모두 error로 만듭니다.

  • Go언어는 컴파일 언어지만, C/C+의 해더파일이 없어서 헤더파일이 조금만
    수정되어도 모두 다시 컴파일하는 그런 문제가 없고, 소스코드를 패키지화하여 변경된 부분만 컴파일하기 때문에 컴파일 시간이 엄청나게 빠릅니다. -> How does Go compile so quickly?

2. 하지만 동적 언어 특성도 가진다 (예: interface -> Duck typing)

Go언어는 interface가 있지만 따로 선언은 하지 않습니다. -> Duck Typing
선언이 없이 인터페이스의 함수를 구현하면 그 인터페이스를 사용한다고 간주합니다.
예를 들어 notifier interface가 정의되어 있습니다.
notifier interfacenotify()메소드를 가지고 있습니다.

  • 특정 struct에서 notify()메소드를 구현했다면,
    structnotifier interface를 구현했다고 간주하는 것입니다.

3. 상속이 없다 (composition만 존재)

Go언어는 상속이 없습니다.
Go언어에서 일반적인 객체 지향 언어에서의 class의 역할을 struct가 맡고 있습니다.
Go의 struct는 상속이 되지 않습니다. 대신 composition이라는 것이 존재합니다.

  • composition이란?
    한 타입과 다른 타입을 결합해서 사용할 수 있게 해주는 것을 의미합니다.
    이는 각 타입간의 결합도를 낮춰주는 효과가 있습니다.
    일반적으로 상속을 사용해서 코딩을 하게 되면 class간의 관계가 tree형태로 만들어집니다.
    따라서 상속을 계속 할수록 계층 구조가 점점 복잡해지고, 그 상황에서 여러가지 문제점이 발생할 수 있습니다.
    `compositio“의 중요성 -> Prefer composition over inheritance?

4. 실행시 가비지 콜렉터 탑재 (Garbage Collection)

Go언어는 바이너리 빌드시 가비지 콜렉터를 내장합니다.
그래서 C/C++처럼 개발자가 메모리 할당 및 해제를 신경쓰지 않아도 됩니다.
또한, Java처럼 가상머신이 필요하지도 않기 때문에, C/C++처럼 빠른 성능을 기대할 수 있습니다.

5. 멀티코어 환경 지원 (goroutine, channel)

최근은 대부분의 컴퓨터가 멀티코어인 시대입니다.
이에 맞게 Go언어는 멀티코어 환경 지원을 위해 만들어진 언어입니다.
Go는 Goroutine이라는 논리적 쓰레드(Thread)를 기본적으로 제공합니다.
사용자는 멀티코어 및 쓰레드 사용에 대해 고민하지 않고, Goroutine을 사용하면 Go 런타임이 알아서 현재 cpu의 코어에 맞춰서 동시에 코드를 실행해줍니다.
Thread를 만들고 실행하고 종료하고 하는 별도의 불편한 과정이 필요없습니다. 사용자는 손쉽게 멀티코어를 이용할 수 있습니다.


이후 포스팅은 다음 포스팅에 하겠습니다.