카테고리 보관물: 서버 설정

QEMU/KVM 복붙 Ctrl+C, Ctrl+V 안 될 때

호스트에서 복사하고 싶은 텍스트를 복사해서 게스트로 붙여넣기 하고 싶을 때에는,

https://spice-space.org

여기에 들어가서 필요한 것을 게스트에 설치해 주면 된다.

게스트OS가 윈도우인 경우에는 Windows guest tools – spice-guest-tools

게스트OS가 리눅스인 경우에는 SPICE vdagent – spice-vdagent-0.21.0.tar.bz2

받아서 설치하면 된다.

QEMU/KVM 디스크 크기 늘리기

변경하고자 하는 VM이 작동중이라면 우선 shutdown 한다.

디스크 파일이 있는 경로는 root 외에는 읽을 수조차 없으므로 super user의 권한이 필요하다. 따라서 아래와 같이 입력한다. 명령문의 예시는 디스크 크기를 30G 늘리는 예제이다.

sudo su
cd /var/lib/libvirt/images
qemu-img resize win_works.qcow2 +30G

위와 같이 하면 “Image resized.”라고 뜬다. 그러면 qemu/kvm의 디스크 이미지 크기는 조정된 것이다.

그 다음엔 해당 VM을 켜고 들어가서 변경된 파티션 조정 작업을 해 주면 된다.

Jenkins 외부 접속을 위한 방화벽 설정

Jenkins를 설치한 후 localhost로는 접속이 되는데, 외부에서 접속이 되지 않는 경우가 있는데, 방화벽에서 해당 젠킨스 서비스를 구동하는 포트를 java에 대해 인바운드 접근을 허용해 주어야 외부 머신에서 접속이 가능하다.

QEMU/KVM 호스트OS와 게스트OS 동일 네트워크에 연결하기 – 브릿지 네트워크 설정

호스트 OS는 Ubuntu 22.04, 그리고 Virtual Machine Manager를 이용해서 VM을 구동하였다.

그런데 네트워크 장치가 기본적으로 NAT로 설정되어 있었다.
그러면 호스트 OS에서 VM으로 접근할 수가 없다.
그럴 땐 macvtap을 이용하면 호스트 OS와 게스트 OS를 동일 네트워크로 연결할 수 있다.
하지만 macvtap을 이용하면 게스트 OS에서 호스트 OS에 엑세스 하지 못하는 문제가 생긴다.

결론은 Bridge 설정을 해야 한다.

  1. 브릿지 넷필터 비활성화
  2. 브릿지 추가
  3. QEMU/KVM에서 브릿지 선택

우선 브릿지 넷필터 비활성화가 필요하다. 다른 설정을 아무리 잘해도 이 문제 때문에 계속 네트워크 설정이 안 되는 문제를 겪었다. 모든 트래픽을 브릿지로 보내고 VM으로 보내려면 이 작업을 꼭 해야 한다. 아래의 내용을 /etc/sysctl.d/bridge-filter.conf로 저장한다.

net.bridge.bridge-nf-call-ip6tables=0
net.bridge.bridge-nf-call-iptables=0
net.bridge.bridge-nf-call-arptables=0

이제는 /etc/udev/rules.d/99-bridge-fileter.rules 파일에 아래와 같이 적어준다.

ACTION==”add”, SUBSYSTEM==”module”, KERNEL==”br_netfilter”, RUN+=”/sbin/sysctl -p /etc/sysctl.d/bridge-filter.conf”

재부팅 해주면 반영된다.

이제 브릿지를 추가해 줄 차례다. nm-connection-editor를 실행한다. 혹시나 GUI를 이용할 수 없는 경우에는 참고자료를 살펴보길 바란다.

  1. + 버튼을 누른 후 Connection Type을 Virtual의 Bridge로 선택한 후, Create를 눌러서 Bridge Connection을 추가한다.
  2. Connection Name을 bridge0, Interface name을 bridge0로 변경해 준다.(bridge0는 예시로 적은 것이다 희망하는 이름을 적어주면 된다.)
  3. bridged connections의 Add 버튼을 누른다.
  4. Connection Type에 Ethernet을 선택.
  5. Connection name에 eth-bridge0 입력.
  6. Device에서 LAN선이 꼽혀 있는 NIC 선택(예, enp8s0). 그리고 Save 클릭.
  7. IPv4 Settings에서 Method를 Manual로 변경한다.
  8. Addresses에 Add를 누른 후 브릿지의 IPv4를 설정해 준다. DNS Server도 설정해 준다.
  9. Save를 눌러서 저장한다.
  10. Bridge에 bridge0이 추가되었고, Ethernet에 eth-bridge0이 추가 되었다면 성공.
  11. terminal에서 nmcli con up eth-bridge0 해주면, 브릿징 완료.
  12. 세팅이 잘 됐는지 확인하고 싶으면, 첫째 nmcli con show해서 bridge0와 eth-bridge0이 올라가있고 enp8s0이 내려가 있는지 확인하면 된다. 그리고, ip a 해보면 공유기와 연결된 NIC에 master bridge0이 보일 것이며, IP는 bridge0에 잡혀 있을 것이다. 이제 브릿지 사용 준비 완료.

이제 마지막이다. QEMU/KVM에서 NIC 설정에 들어간다.

  1. Network source를 Bridge device로 선택한다.
  2. Device name은 위에서 설정한 브릿지 이름을 적어준다.(위에서는 bridge0)
  3. Device model을 e1000e로 선택한다.
  4. Apply를 눌러서 적용한 후, VM을 실행하면 된다.

끝.

참고자료
https://levelup.gitconnected.com/how-to-setup-bridge-networking-with-kvm-on-ubuntu-20-04-9c560b3e3991

https://wowgold-seller.com/ko/stories/285-how-to-use-bridged-networking-with-libvirt-and-kvm

리눅스 운영체제에서 타임존 설정하기

클라우드 서비스를 이용하게 되면 기본적으로 시간은 UTC +00:00 기준으로 설정된다. 한국시간 기준으로 타임존을 설정하려면 timedatectl 명령어를 사용하면 된다.

우선 timedatectl만 입력하면 상태값들을 확인할 수 있다.

그리고, 아래와 같이 입력하면 Asia/Seoul 기준의 타임존 설정이 끝난다.

sudo timedatectl set-timezone Asia/Seoul

Nginx 로드 밸런싱 – https 서버 여러 대인 경우

처음엔 아래와 같은 방식으로 작성했는데, 이렇게 하는 경우 proxy_pass를 통해 https의 해당 도메인으로 정확히 연결되지 않는 현상을 발견하였다. 현재 사용할 서버는 PHP 아닌데, 왜 PHP가 뜨는 거지? 오잉? 싶었는데, 다른 서비스 용으로 PHP가 돌아가고 있었다. 즉, 엉뚱한 도메인으로 연결되고 응답으로 404 Not Found를 돌려받고 있었다. Oh my gosh! 왜 이런 현상이 생기는 것이지? 이건 분명 도메인으로 넘어가지 않고 IP로 넘어가서 발생한 현상일 듯한데 싶었다. 그렇다면 어떻게 이걸 명확하게 도메인으로 넘겨줄 수 있을지 고민이 되었다.

http {
  ...
  upstream servers {
    server first.myserver.com:443;
    server second.myserver.com:443;
  }

  server {
    listen 443 ssl;
    location / {
      proxy_pass https://servers;
    }
    ...
  }

}

그리고서 구글링을 하다가 힌트(https://stackoverflow.com/questions/29071168/nginx-upstream-with-http-https/65767299)를 발견한 후 아래와 같이 수정하였다.

http {
  ...
  upstream servers {
    server 127.0.0.1:8081;
    server 127.0.0.1:8082;
  }

  server {
    listen 443 ssl;
    location / {
      proxy_pass http://servers;
    }
    ...
  }

  server {
    listen 8081;
    location / {
      proxy_pass https://first.myserver.com;
    }
  }

  server {
    listen 8082;
    location / {
      proxy_pass https://second.myserver.com;
    }
  }

}

드디어 로드 밸런싱이 원하는대로 작동하기 시작했다.

정리해보면, nginx의 소스코드를 까보지 않아서 왜 이런 현상이 발생하는지는 정확히 모르겠지만, 추론컨대 전자의 경우 domain으로 작성하지만 IP와 포트로만 처리하는 것으로 보인다. 왜냐하면 동일 머신에 필자가 운용중인 다른 서비스로 접근하는 것을 확인했으니 말이다. 후자의 경우는 각각의 proxy 서버가 명확하게 목적지를 가리키고 있으므로 문제가 발생하지 않았던 것으로 보인다.

단일 서비스만 운용하는 경우에는 별 문제가 되지 않을 수 있겠지만, https로 이용하는 서비스가 여러 개 있다면 필자와 같이 문제가 발생할 수 있다.

Jenkins – Publish over SSH 플러그인 키 설정

Publish over SSH는 Jenkins에서 빌드를 마치고, 특정 서버로 배포를 할 때 사용하는 플러그인이다.

SSH 접속을 위해서는 User ID와 비밀번호 또는 개인키/공개키가 필요하다. 우리는 개인키/공개키를 사용할 것이므로 비밀번호는 필요하지 않다.

혹여나 사용하는데 필요한 개인키/공개키 쌍이 준비되어 있지 않다면, 그림 1과 같이 ssh-keygen을 이용해서 키 쌍을 준비해야 한다.

그림 1. ssh-keygen 이용하여 개인키/공개키 쌍 만들기

* Publish over SSH 플러그인을 우선 설치한다.

* Jenkins 관리 > 시스템 설정 > SSH Servers로 이동한다.

* SSH Servers에 항목이 없다면, “추가” 버튼을 클릭한 후, 아래의 내용을 기입한다.

Name에는 식별할 수 있는 이름을 적어준다.
Hostname에 접속할 IP나 도메인을 적어준다.
Username에는 접속할 사용자 이름을 적어준다.
Remote Directory에는 접속하고자 하는 디렉토리를 입력한다.

그림 2. SSH Server 기본 정보 입력 예시

* 우측 하단에 있는 “고급” 버튼을 누르면 고급 항목들이 펼쳐진다.

그림 3. 고급 버튼 위치

* “Use password authentication, or use a different key” 여기에 체크를 해 준 후,
Key에 SSH에 사용할 개인키를 붙여넣어주면 Jenkins 상의 개인키 설정이 끝난다.

그림 4. 개인키 입력 화면

* 배포 대상인 서버로 접속한 후, 그림 5와 같이 사용하려는 공개키를 ssh-rsa부터 끝까지 모두 복사해서 ~/.ssh/authorized_keys 파일에 공개키를 한 줄 추가해 준다. authorized_keys 파일이 없다면 새로 작성하면 된다.

그림 5. 공개키 내용 열람

* Jenkins의 SSH Server 항목 우측 하단에 Test Configuration 버튼을 누른다.

그림 6. Test Configuration 버튼 위치

* 왼쪽에 Success라고 뜨는지 확인했다면 SSH 접속을 위한 개인키/공개키 설정이 끝난다.

그림 6. 성공 메시지

만약 성공하지 못한다면, Success 라는 내용 대신에 오류 메시지로 문제점을 알려줄 것이다. 해당 오류에 대해 구글링 후 문제를 해결하면 된다.

LINE Works에서 Mailgun 활용하여 Gmail로 옮기면서 발생한 이슈

LINE Works가 이제 유료화를 보름 앞두고 있다.
그래서 G-Suite으로 이사할까 했지만, 어차피 유료고 업무용 메일도 아닌데 굳이 돈을 쓸 필요 있을까 싶어서 대안을 찾다가, Mailgun과 Gmail을 사용해서 개인 메일 세팅이 가능한 내용들을 검색하였다. LINE Works 때문에 벌써 고민하고 포스팅하신 분들이 있었다. 두 분께 이 자리를 빌어 감사드린다.

http://wequlo.blogspot.com/2017/04/mail-gun.html
http://recordingbetter.com/aws/2017/09/22/custom-domain-email-gmail-mailgun

위의 두 포스팅을 읽고 mailgun 세팅을 완료했다.

이제 테스트할 단계다. 그래서 Gmail에서 mailgun에 세팅한 개인 이메일 계정으로 메일을 보냈다.

“550 5.7.1 Relaying denied” 라는 메시지와 함께 메일이 들어오는 문제가 있었다.

이건 뭐지 싶었다. 일단 테스트를 3통 했는데, 모두 오류 메일이 함께 들어오는 것이다. 이건 뭔가 문제가 있는 거 같았다. 일시적이었을 거라 생각하며 마지막으로 한 통의 메일을 더 발송했는데, 메일이 아예 들어오지를 않는 것이다. 550 5.7.1의 오류 메일도 오지 않는 것이다. 직감적으로 Gmail에서 차단한 것이구나 싶었다.

그래서 해당 오류가 무슨 의미인지 찾아보기 시작했다. 아래 참고자료의 Ask leo의 내용을 읽어보면 쉽게 이해할 수 있다.

일단 이 문제가 발생한 기본적인 이유는 Gmail 발송 서버 -> 메일건(osg.kr) -> Gmail 수신 서버의 흐름으로 메일이 전달되는 구조에서 출발한다.

문제는 마지막으로 osg.kr(mailgun)에서 gmail로 relay하는 부분인데, gmail에서는 osg.kr에서 relaying하는 게 누구인지 신원 확인이 되지 않은 상황인 것이다. 신원이 확인되지 않은 메일에 대해서 Gmail 수신 서버는 차단하는 것이다. 그래서 “550 5.7.1 Relaying  denied” 메일을 세 번 받은 이후에는 더 이상 메일이 들어오지 않는 것이었다.

해결책은 Gmail 수신 서버에 osg.kr을 인증된 도메인으로 설정해 주면 된다.

1. https://postmaster.google.com/managedomains
2. 우측 하단의 + 표시를 누른다.
3. 인증할 도메인을 입력해 준다. 필자는 osg.kr을 사용하므로 osg.kr을 입력하였다.
4. NEXT 버튼을 누르면, DNS TXT에 설정할 값을 알려준다.
5. 해당 값을 인증할 도메인의 네임서버에 TXT 값으로 설정해 준다. 필자는 Vultr에서 네임서버를 사용하고 있으므로, vultr에서 ns 세팅을 하였다.
6. Verify 버튼을 누른다.

이제 Gmail에 들어가서 인증한 도메인의 메일로 메일을 발송해 본다. 아주 잘 들어오면 세팅이 끝난 것이다. 일단 필자는 이렇게 문제를 해결했다.

참고자료:
http://ask-leo.com/what_does_relaying_denied_mean.html
https://productforums.google.com/forum/#!topic/gmail/v8wVQIa0PTA

Bitbucket 저장소와 Jenkins webhook 연동 – proxy

Jenkins와 Bitbucket Repository를 Webhook으로 연동했을 때의 문제는 webhook 조건을 pull request merged로 설정하면 브랜치 여부에 관계없이 webhook을 날린다는 것이다. 필자가 앞서 포스팅 한 글(https://blog.osg.kr/archives/80)에서 사용하는 방법도 마찬가지다.

안드로이드 프로젝트의 dev 브랜치가 pull request 됐을 때 개발용 앱을 빌드하고, master 브랜치에는 tag가 push 됐을 때 상용 앱을 빌드하도록 하고 싶다면? 어떻게 해야 할까? 이는 실제 필자가 서비스 개발에서 활용하고 있는 방법이다.

필자는 Proxy 서버를 Node.js로 간단히 구축하여 개발서버에서 구동하고 있다. Bitbucket에서는 webhook을 날리는 request body를 로그로 남겨준다. 로그에 기록된 body를 참조해서 해당 json을 파싱해서 활용하면 된다.

프록시 작동 원리는 다음과 같다. 개발용 앱 빌드의 경우 Bitbucket에서는 브랜치에 상관없이 pull request가 merge되면 webhook을 Node.js로 구축한 Proxy 서버에 보낸다. 프록시 서버는 body의 내용을 확인해서 dev 브랜치로 머지된 것인 경우에만 Jenkins 서버로 다시 Webhook을 걸어준다.

상용 앱 릴리즈 시에는 Bitbucket에 tag가 push되면 Proxy로 일단 webhook이 걸린다. 프록시 서버에서 body의 내용을 확인해서 master branch에 태깅됐을 경우에만 Jenkins로 webhook을 걸어준다.

단순히 도식화하면 아래와 같다.

Bitbucket Webhook > Node.js proxy > Jenkins task item

물론 Proxy 서버는 꼭 Node.js를 쓸 필요는 없다. 자신이 쓰기 편한 프레임워크를 사용하면 된다.

AWS EC2로 웹 서버 띄우기 전에 해야 할 일

필자는 AWS의 EC2 인스턴스를 제대로 활용해 볼 기회가 없었던, 그래서 AWS 초짜이다. EC2 인스턴스를 새로 생성해서 서비스해야 할 일이 생겨서 웹서버를 구축하다가 AWS 서비스의 구조를 잘 몰라서 잠시 고생을 했다. 웹서버를 띄웠는데 인스턴스와 IP는 어떻게 연결해 주어야 할 지, 도메인 세팅을 다 해 주었는데도 왜 접속이 되지 않았는지 고민하게 되었다.

결론은 AWS를 몰라서 생긴 이슈였다. 필자가 경험한 것을 바탕으로 AWS EC2 사용과정에서 꼭 필요한 과정들을 간단히 정리해 보았다. 혹여나 필자와 같은 처지에 있는 분들께 도움이 되길 바라는 마음으로 과정을 공유하고자 한다.

1. EC2 인스턴스를 생성한다.

2. ElasticIP를 추가한 후 생성한 인스턴스를 연결해 준다.

AWS의 인스턴스를 멈추고 다시 시작하면 새로운 내부 IP가 부여된다. 고정된 IP로 서비스하려면 엘라스틱 IP 서비스를 사용해야 한다.

3. 네임서버에 서비스하고자 하는 도메인에 대한 주소를 엘라스틱IP에서 할당받은 IP로 설정해 준다.

카페24나 도레지 등에서 네임서버를 설정할 수 있으면 굳이 라우트 53은 사용하지 않아도 된다.

4. 보안 그룹 페이지에 가서 서비스하고자 하는 포트를 열어준다.

기본적으로 EC2는 ssh 사용을 위해 22번 포트만 열어준다. 따라서 추가로 서비스를 제공하려면 해당하는 포트를 inbound에서 열어줘야 서비스가 가능하다.