2014년 3월 7일 금요일

vagrant 를 이용하여 개발환경 만들기

vagrant 를 이용하여 맥프로에 개발 환경을 만들었다. 그 과정을 간단하게 정리해 본다.

우선 vagrant 를 다운로드 받자.

http://www.vagrantup.com/downloads.html

그리고 virtualbox 를 다운로드 받아 설치한다.

https://www.virtualbox.org/wiki/Downloads

개발 환경을 만들기 위해서 생성할 Host 의 필요한 네트워크 조건은

  • 인터넷이 되어야 한다.
  • Host와 Guest간에 연결되어야한다.
  • 독립 네트워크만 구성하면 된다.
그런데 VirtualBox 의 네트워크에는 다음의 3가지 사항이 있었다.
  • Bridged Networking : 위의 2가지 조건을 만족하나 네트워크 환경을 만들고 IP 구성을 하여야 한다. 네트워크 환경을 만들수 없기 때문에 개발환경에는 부적합했다.
  • NAT(Network Address Translation) : Host 와 Guest 간에 연결이 불가하나 인터넷이 가능하다.
  • Host Only Networking : Host 와 Guest 간에 연결이 가능하다 인터넷이 불가능하다.


개발환경을 위해 필요한 네트워크 구성은 NAT 와 Host Only 를 동시에 사용하면 독립 네트워크도 구성하고 인터넷도 사용할 수 있게 만들수 있다.
vagrant 를 이용하여 구성해 보았다. 만들려는 서버는 우선 AppServer 로 가장 기본적인 Tomcat 와 mysql 이 설치된 개발서버였다.
편의를 위해 boxes 폴더를 만들고 appserver 폴더를 만들었다.

mkdir boxes
cd boxes
mkdir appserver
cd appserver

그리고 적당한 vagrant box 를 vagrantbox.es 에서 선정하였다. ubuntu 를 주로 사용하기에 "Ubuntu precise 64 Virtualbox" 를 선택했다.

vagrant box add appserver http://files.vagrantup.com/precise64.box

다운로드 완료후 초기화 실행

vagrant init appserver

이렇게 하면 appserver 폴더에 Vagrantfile 이 생성된다. 이를 아래와 같이 추가하였다.

Vagrant::Config.run do |config|
  config.vm.box = "appserver"
  config.vm.box_url = "http://files.vagrantup.com/precise64.box"
  config.vm.network :hostonly, "33.33.33.10"
end


IP 는 취행이니 편하게 설정한다. 위와 같이 설정하면 네트워크가 NAT 와 Host Only 를 모두 사용할 수 있다. Virtualbox 를 살펴보면 어댑터1은 "NAT"로 어댑터2는 "호스트 전용 어댑터"로 설정되어 있는 것을 확인할 수 있다.

Vagrantfile 를 수정한 후 해당 VM을 실행하였다.

vagrant up

그리고 접속하기 

vagrant ssh

vagrant 라는 계정으로 접속되는 것을 확인할 수 있다. 참고로 비밀번호는 vagrant 이다.

이런 방식으로 dbserver 를 포함하여 몇개의 서버를 더 만들었다.

시간이 될 때 hadoop와 zookeeper 를 분산 모드로 설치하는 것을 하도록 한다.

Java Virtual Machine 공부 하다 그려본 다이어그램

Java Virtual Machine 를 공부할 필요가 있어서 공부하다 한눈에 볼수 있도록 다이어그램을 그려봤다.
완벽하지는 않지만 적어도 내가 보고 기억해 낼 수 있도록 만들었다.

나중에 좀 더 잉여시간이 된다면 차근차근 정리해야겠다.


2014년 2월 18일 화요일

docker 맛보기

맥북프로를 구매했다.
좀 더 다양하게 여러가지를 수행하고 싶은데 맥북에어로서는 한계가 있어서 맥북프로를 구매했다.

그리고 docker를 설치해보기로 했다.

참고 페이지 : http://docs.docker.io/en/latest/installation/vagrant/

1. virtualbox 를 다운로드 받아 설치 : https://www.virtualbox.org/

2. vagrant 를 다운로드 받아 설치 : http://www.vagrantup.com/

3. git 으로 docker source 다운로드
    git clone https://github.com/dotcloud/docker.git

4. 다운로드 받은 docker 로 이동
    cd docker

5. docker 폴더를 살펴보니 이상한 것들이 많다.
AUTHORS Vagrantfile dockerinit nat tags.goCHANGELOG.md api dockerversion networkdriver tags_unit_test.goCONTRIBUTING.md archive docs pkg utilsDockerfile auth engine registry utils.goFIXME buildfile.go execdriver runconfig utils_test.goLICENSE commands_unit_test.go graph.go runtime.go vendorMAINTAINERS config.go graphdriver server.go version.goMakefile container.go hack server_unit_test.go volumes.goNOTICE container_unit_test.go image.go sorter.goREADME.md contrib integration state.goVERSION docker links sysinit

6. vagrant 실행
    vagrant up

  • vagrant 를 실행하면 ubuntu 64bit 를 다운로드 받는다.
  • 해당 ubuntu 에는 docker 가 이미 설치되어 있다.    

7. vagrant 를 통해 ubuntu 에 접속
    vagrant ssh

8. 이제부터 docker 를 공부해서 사용해 본다.
    아래 Hello World 를 출력하는 것 외에도 많은 예제가 있으니 참고하면 된다.
    http://docs.docker.io/en/latest/examples/hello_world/

그런데 중간에 나온 vagrant 를 좀더 알아야겠다.

쉽게 이해할 수 있는 발표자료 : http://www.slideshare.net/arawnkr/vagrant-chef
조대협님의 블로그 : http://bcho.tistory.com/806
vagrant box list : http://www.vagrantbox.es/

위의 box list 를 활용하여 개발환경을 구축하는 방법 : http://ppiazi.tistory.com/m/post/view/id/230

이로서 맥북프로에서 다양한 개발 환경을 만들어 사용할 수 있게 되었다.
하지만 아직 네트워크에 대하여는 지식이 매우 부족한 편이다.
어제 갔던 Openstack Day In Korea 에서 네트워크에 대한 질문을 하고 싶었는데 여건이 안되어서 물어보지 못했다.

나중에 네트워크에 대하여 좀 더 공부해 봐야겠다.


2014년 2월 13일 목요일

ASM 4.0 Example - Hello World 주석 달기

import java.io.FileOutputStream;
import java.io.PrintStream;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;

/**
 * @author Eric Bruneton
 */
public class Helloworld extends ClassLoader implements Opcodes {

public static void main(final String args[]) throws Exception {

        // 아래의 소스에 대하여 자바 클래스 파일에 해당하는 바이트 코드를 만들기
        /**********************************************************************
        public class Example {
            public static void main (String[] args) {
                System.out.println("Hello world!");
            }
        }
        **********************************************************************/

// ClassWriter 만들기 - Object 를 상속 받아서
ClassWriter cw = new ClassWriter(0);
        // visit(int version, int access, String name, String signature, String superName, String[] interfaces)
cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null);

// 생성자 MethodWriter 만들기
        // visitMethod(int access, String name, String desc, String signature, String[] exceptions)
MethodVisitor mw = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);

        // visitVarInsn(int opcode, int var)
        // opcode 는 ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE, RET 중 선택사용
        // opcode 참조 : http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html
        // 'this' 변수 지정
mw.visitVarInsn(ALOAD, 0);

// super class constructor
        // visitMethodInsn(int opcode, String owner, String name, String desc)
        // opcode 는 INVOKEVIRTUAL, INVOKESPECIAL, INVOKESTATIC, INVOKEINTERFACE 중 선택사용
mw.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");

        // visitInsn(int opcode)
mw.visitInsn(RETURN);

        // visitMaxs(int maxStack, int maxLocals)
        // 메소드의 최대 스택 사이즈
        // 메소드를 위한 로컬 변수의 최대 사이즈
mw.visitMaxs(1, 1);

mw.visitEnd();

// main 함수 만들기
        // visitMethod(int access, String name, String desc, String signature, String[] exceptions)
mw = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);

// System 클래스의 'out' field 사용
        // visitFieldInsn(int opcode, String owner, String name, String desc)
        // opcode 는 GETSTATIC, PUTSTATIC, GETFIELD, PUTFIELD 중 선택사용
mw.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");

// "Hello World!" String 상수 사용 (ldc instruction)
        // ldc pushes a one-word constant onto the operand stack. int, float, String 등
  mw.visitLdcInsn("Hello world!");
        
// 'prinln' 수행
mw.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");

        mw.visitInsn(RETURN);

        // visitMaxs(int maxStack, int maxLocals)
        // 메소드의 최대 스택 사이즈
        // 메소드를 위한 로컬 변수의 최대 사이즈
mw.visitMaxs(2, 2);

mw.visitEnd();

// 바이트코드 값 얻기
byte[] code = cw.toByteArray();

// class 파일 만들기
        FileOutputStream fos = new FileOutputStream("Example.class");
fos.write(code);
fos.close();

// 클래스로더로 읽어 들이기
        Helloworld loader = new Helloworld();
Class<?> exampleClass = loader.defineClass("Example", code, 0, code.length);

// 로딩된 클래스의 main 메소드 수행하기
exampleClass.getMethods()[0].invoke(null, new Object[]{null});

// ------------------------------------------------------------------------
// GeneratorAdapter를 이용하여 만들기 (편리하지만 느리다 ㅡ.ㅡ;;)
// ------------------------------------------------------------------------
        
cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
cw.visit(V1_1, ACC_PUBLIC, "Example", null, "java/lang/Object", null);

        // 생성자 만들기
Method m = Method.getMethod("void <init> ()");
        // GeneratorAdapter(int access, Method method, String signature, Type[] exceptions, ClassVisitor cv)
GeneratorAdapter mg = new GeneratorAdapter(ACC_PUBLIC, m, null, null, cw);
mg.loadThis();
mg.invokeConstructor(Type.getType(Object.class), m);
mg.returnValue();
mg.endMethod();

// main 함수 만들기
m = Method.getMethod("void main (String[])");
        // GeneratorAdapter(int access, Method method, String signature, Type[] exceptions, ClassVisitor cv)
mg = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC, m, null, null, cw);
mg.getStatic(Type.getType(System.class), "out", Type.getType(PrintStream.class));
mg.push("Hello world!");
mg.invokeVirtual(Type.getType(PrintStream.class), Method.getMethod("void println (String)"));
mg.returnValue();
mg.endMethod();

cw.visitEnd();

        // 바이트코드 값 얻기
code = cw.toByteArray();

        // 클래스로더로 읽어 들이기
loader = new Helloworld();
exampleClass = loader.defineClass("Example", code, 0, code.length);

        // 로딩된 클래스의 main 메소드 수행하기
exampleClass.getMethods()[0].invoke(null, new Object[]{null});
}
}


2014년 2월 12일 수요일

node.js 살펴보기

node.js 에 대하여 많이 듣기는 했으나 제대로 머리속에 정리가 안되어 있어서 정리를 해보도록 하자.

Node.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.

node.js  확장성 있는 네트워크 어플리케이션 개발을 쉽고 빠르게 할 수 있도록 지원하는 자바스크립트 런타임 기반의 플랫폼이다. (특히 server-side 에 유용하다.)
event-driven, non-blocking I/O model 을 사용한다. (기타 좋은 말은 영문으로... ^^)

위키 : http://ko.wikipedia.org/wiki/Node.js

음... 잘 모르겠다 ㅡ.ㅡ;;

그럼 예제를 보면 좀 더 이해가 가리라..... 역시 node.js 홈페이지(http://www.nodejs.org/) 의 예제를 보도록 하자.


  • 웹 서버 띄우기
var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1337, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1337/');

자바스크립트를 이용하여 'http' 프로토콜을 지정하고 createServer 를 통해 서버를 만들었다. 웹 서버니까 listen 으로 포트를 열어두고. 서버의 요청이 있는 경우 'Hello World'를 출력하는 함수를 만들어 두었다.
간단한 예제이지만 쉽게 이해가 갈 것이다. 서버를 생성할 때 function 에 필요한 로직을 두면 웹 어플리케이션이 되는 것이다. 물론 이때 MVC 패턴 등을 이용하여 만들어 두면 훨씬 쉽게 작성할 수 있다. 아직 찾아보지는 않았지만 아마도 잘 정리된 개발 패턴이 있거나 node 기반의 프레임워크가 존재할 것이다. 꼭 찾아보자...

네트워크 어플리케이션을 작성할 수 있다고 하지 TCP 기반의 어플리케이션을 만드는 예제를 살펴보자


  • TCP 서버 띄우기 
var net = require('net');

var server = net.createServer(function (socket) {
  socket.write('Echo server\r\n');
  socket.pipe(socket);
});

server.listen(1337, '127.0.0.1');

명확하고 심플하다. net 객체를 받아서 TCP Server 를 만들었다. listen 함수를 통해 아이피와 포트를 지정하였다. 아직 살펴본 것은 아니지만 server객체로 부터 request 를 받아서 처리하는 로직을 주도 response 객체를 만들어 전달하면 응답하는 형태일 것이라는 추정이 된다. 아님 말구. ^^

자바스크립트만을 이용해서 어플리케이션을 만들 수 있고, 복잡한 서버 설정을 하는 것이 아니라 코드로 설정 정보를 세팅하는 방식이어서인지 매무 심플하고 명료하다.

관련 API 문서는 한글화 된 버전이 있다.

http://nodejs.sideeffect.kr/docs/

Node.js 관련 잘 정리된 사이트 : http://octoberskyjs.github.io/home/


docker 를 따라가기

어떤 분의 페북글에 docker.io 에 대하여 언급이 나와 이를 찾아보게되었다.

도커(docker)는 기존의 가상화 어플리케이션에서 하드웨어 전체를 가상화하는 것과 달리 리눅스 컨테이너를 활용하고 있는 도커는 아주 빠르고 쉽게 가상화 환경을 사용할 수 있도록 해준다.

http://docker.io

docker 에 대한 발표자료

http://www.slideshare.net/modestjude/dockerat-deview-2013

발표 내용을 보다가 궁금해진 hipache. 분산 프록시

https://github.com/dotcloud/hipache


다시 docker 에 대한 개념 정리... 역시 조대협님!!!

http://bcho.tistory.com/805

이어서 등장한 vagrant

http://bcho.tistory.com/806


다음에 도전하고 싶은 것은

맥북프로를 구매하여 vagrant 와 docker 를 이용하여 개발 장비 구축

Reference

* http://judekim.tistory.com/category/Programmer/Docker



2014년 2월 7일 금요일

ASM 4.0 Guide - 1 Days

1. introduction

1.1 Movivations

ASM 은 자바 바이트코드 엔지니어링 라이브러리(a java bytecode engineering library)으로 다음의 이점이 있다.


  • Program analysis : 파싱에서 부터 애플리케이션의 잠재적인 버그를 찾거나, 사용하지 않는 코드, 역공학에 사용
  • Program generation : 일반 컴파일러나 Just in Time 컴파일러 같이 분산 프로그래밍에서 사용할 스텁, 스켈레톤 컴파일러가 사용할 프로그램을 작성
  • Program transformation : 프로그램을 최적화 하거나 AOP같이 성능 모니터링 이나 디버깅용 코드를 추가
그것도 runtime 시에 가능하다.

1.2 Overview

1.2.1 Model

ASM 라이브러리는 2개의 API 를 제공한다.

  • core API : event based model
- 연속적인 이벤트로 클래스를 표현한다.
- 각 이벤트는 클래스의 특정 구성 요소를 나타낸다.
- 이벤트 기반 API는 사용 가능한 이벤트, 반드시 따라야 하는 순서, 파싱할 엘리먼트 당 하나의 이벤트를 생성하는 클래스 파서, 연속적인 이벤트에서 컴파일된 클래스를 생성하는 클래스 작성기를 제공한다.
  • tree API : object based model
- 객체 트리로 클래스를 표현한다.
- 각 객체가 클래스 구성 요소를 나타낸다.
- 각 객체는 자신의 하위 구성 요소에 대한 객체들을 나타내는 레퍼런스를 가지고 있다.
- 객체 기반 API는 연속적인 이벤트 모델을 객체 트리 모델로 변경하는 하거나 그 반대로 변경하는 기능을 제공한다.
- 객체 기반 API는 이벤트 기반 API를 근간으로 만들어졌다.

이벤트 기반 API가 더 좋다.

- 객체 기반 API 보다 빠르고 메모리 소비가 적다.
- 클래스 변형이 객체 기반 모델 보다 어렵다. 한번에 한 엘리먼트만 조작하니까.


1.2.2 Organization


  • asm.jar
org.objectweb.asm, org.objectweb.asm.signature
event based API
클래스 파서, 클래서 생성기(class writer) 등의 컴포넌트

  • asm-util.jar 
org.objectweb.asm.util

  • asm-common.jar
 org.objectweb.asm.commons
미리 정의해 둔 클래스 트랜스포머

  • asm-tree.jar 
 org.objectweb.asm.tree
object based API

  • asm-analysis.jar 
tree API 기반의 클래스 분석 프레임워크와 미리 만들어 둔 클래스 분석기 제공