이런 경험 다들 있으시죠??
그러면 한번 해봅시다!
- Client 용 web-service : root
- API 전용 web-service : api
- admin web-service : admin
ㅁ 어서 오십쇼! New 구성원님! 개발하기 전에 아래 내용을 셋팅해 주시죠!
보통 새로운 구성원이 오면 개발환경 셋팅을 도와 주어야 합니다. 지금 경우에는 MySQL, Tomcat, Angular 만 셋팅하면 되는 아주 쉬운(?) 상황으로 가정할게요. 하지만 아키텍처가 조금만 복잡해져도 Redis, HDFS 서버, Mongo 등 다양한 셋팅이 붙을 수도 있습니다!
- Angular 1.x 개발을 위한 Grunt-server
- angular 1.4.x
- sass
- bower
- npm ( package management 용 )
- Spring MVC
- MySQL 5.7.x
- 스프링이 돌아갈 WAS - 여기서는 Tomcat 8.0.x을 사용
ㅁ 이제는 docker-compose OR vagrant 를 이용해서 편하게 해볼게요!
ㅇ docker-compose 설치하기
ㅇ 이따가 한번 써볼 vagrant 도 설치하기
근데 이게 뭔지는 알고 가자!
Docker-compose 란?
ㅁ docker compose 를 사용하는 방법
- Docker file 에 내가 사용할 앱 환경을 정의한다. 여기서 앱 환경이라 함은 내가 하나의 서비스를 돌리는데 필요한 어플리 케이션들을 의미한다 ( 즉, 위에서는 MySQL, Tomcat, Angular 돌리는데 필요한 grunt, npm 등이 되겠다. )
- docker-compose.yml 파일에 내가 사용할 앱들을 묶은 서비스를 정의한다.
- docker-compose up 명령어를 실행한다!
Sample ( docker-compose.yml )
version: '2' services: web: build: . ports: - "5000:5000" volumes: - .:/code - logvolume01:/var/log links: - redis redis: image: redis
Vagrant 란?
Vagrant is a tool for building complete development environments. With an easy-to-use workflow and focus on automation, Vagrant lowers development environment setup time, increases development/production parity, and makes the "works on my machine" excuse a relic of the past.
0단계 : Spring MVC 프로젝트 생성하기
1단계 : Dockerfile 만들기
MySQL 용 Dockerfile
FROM mysql:5.6 # Copy the database initialize script: # Contents of /docker-entrypoint-initdb.d are run on mysqld startup ADD Dump/ /docker-entrypoint-initdb.d/ # Default values for passwords and database name. Can be overridden on docker run # ENV MYSQL_ROOT_PASSWORD=my-secret-pw # Not defaulted for security reasons! ENV MYSQL_DATABASE=your_db_name ENV MYSQL_USER=your_user_name ENV MYSQL_PASSWORD=your_user_password
- mysql 5.6 버전을 base image 로 합니다.
- Dump 폴더안에 sql 을 /docker-entrypoint-initdb.d/ 로 옮겨놓으면 mysql 서버가 start 될 때 저 안의 sql 문을 순차적으로 실행시킵니다.
- 그리고서 사용할 db와 계정 정보를 ENV 를 통해 추가합니다.
Tomcat 용 Dockerfile
#FROM pietvandongen/docker-tomcat-development:latest FROM tomcat:8-jre8 MAINTAINER Sophia Parafina# tomcat-users.xml sets up user accounts for the Tomcat manager GUI # and script access for Maven deployments # ADD tomcat/tomcat-users.xml $CATALINA_HOME/conf/ # ADD tomcat/catalina.sh $CATALINA_HOME/bin/ ADD tomcat/run.sh $CATALINA_HOME/bin/run.sh RUN chmod +x $CATALINA_HOME/bin/run.sh # add MySQL JDBC driver jar ADD tomcat/mysql-connector-java-5.1.36-bin.jar $CATALINA_HOME/lib/ # create mount point for volume with application # RUN mkdir $CATALINA_HOME/webapps/UserSignup # add tomcat jpda debugging environmental variables ENV JPDA_OPTS="-agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n" #ENV JPDA_ADDRESS="8000" #ENV JPDA_TRANSPORT="dt_socket" # start tomcat7 with remote debugging EXPOSE 8080 CMD ["run.sh"]
- tomcat:8-jre8 이미지를 base 이미지로 합니다.
- 톰캣 실행 쉘을 추가하고, 실행 권한을 부여한다.
- mysql connector 를 추가해준다.
- 원격 디버깅을 위해 JPDA 옵션을 추가해준다. 여기서는 8000 포트를 통해 접근할 수 있도록 설정하였다.
- 8080 포트를 host 와 연결한다. ( 외부로 노출 되진 않는다! 외부로 노출하는 설정은 docker-compose.yml 파일에서 하도록 한다. )
2단계. docker-compose.yml 파일 만들기
version: "2" services: database: build: context: ./registration-database image: registration-database # set default mysql root password, change as needed environment: MYSQL_ROOT_PASSWORD: password # Expose port 3306 to host. Not for the application but # handy to inspect the database from the host machine. ports: - "3306:3306" restart: always webserver: build: context: ./registration-was image: registration-webserver # mount point for application in tomcat volumes: - ./root/target/root:/usr/local/tomcat/webapps/ROOT - ./api/target/api:/usr/local/tomcat/webapps/api - ./admin/target/admin:/usr/local/tomcat/webapps/admin - ./registration-was/tomcat/logs:/usr/local/tomcat/logs links: - database:registration-database # open ports for tomcat and remote debugging ports: - "8080:8080" - "8000:8000" restart: always
- version 은 왠만하면 2로! ( 참조 : https://docs.docker.com/compose/compose-file/#/version-2 ) 이게 내가 만든 서비시들의 version 이 아니라 compose 의 버전을 몇을 쓸건지 입니다. version 1은 곧 deprecated 될 예정이라고 하네요 :)
- database ( MySQL ), webserver ( tomcat ) 서비스들을 정의합니다.
- build > context : Dockerfile 을 포함할 path 입니다. git repository 의 url 로 정의해도 됩니다.
- image : 이미지 name 입니다. 추후 links 설정시, DB connection 시 필요합니다.
- ports : (HOST:CONTAINER) 형식으로 내 호스트로 들어온 포트를 container 의 포트로 포워딩 해주는 설정입니다.
- restart : always 설정은 container 의 상태에 상관없이 무조건 restart 하겠다는 의미입니다.
- links : container 에서 다른 container 를 동일한 subnet 이라 가정시 바라 볼 수 있는 hostname 입니다. 아래서 조금더 설명해 보도록 하죠!
Links 옵션
3단계. Web-Project property 수정하기
database-connection.properties
... jdbc.url=jdbc:mysql://127.0.0.1:3306/my_db_name?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8 jdbc.username=my_name jdbc.password=my_password
보통 이런식으로 내 로컬주소:포트 를 mysql connection 정보에 적게 됩니다. 하지만 위와 같이 docker-compose 파일을 설정한 경우 위와 같이 connection 정보가 유지 되면 tomcat 에 올라간 웹 서비스가 cannot connect MySQL... 이란 에러를 뱉습니다. 왜 그럴까요...?
... jdbc.url=jdbc:mysql://registration-database:3306/my_db_name?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8 jdbc.username=my_name jdbc.password=my_password
... jdbc.url=jdbc:mysql://database:3306/my_db_name?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8 jdbc.username=my_name jdbc.password=my_password
4단계 : docker compose up
$ docker-compose up -d Starting binswas_database_1 Starting binswas_webserver_1 $ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e0bf7404c258 registration-webserver "run.sh" 3 minutes ago Up 12 seconds 0.0.0.0:8000->8000/tcp, 0.0.0.0:8080->8080/tcp binswas_webserver_1 cf6a2cc3c4b1 registration-database "docker-entrypoint.sh" 3 minutes ago Up 12 seconds 0.0.0.0:3306->3306/tcp binswas_database_1
따로 -d 옵션을 붙이지 않은 경우 로그가 찍히며 가동됩니다. 그때는 ctrl + c 만 눌러도 종료된것과 같습니다.
-d 옵션을 줘서 실행한경우 끄는 명령어는 stop 입니다.
$ docker-compose stop
$ docker-compose down
5단계 : angular 개발 환경 셋팅
$ brew update $ brew install rbenv $ rbenv install 2.0.0-p451 $ rbenv rehash $ rbenv global 2.0.0-p451 $ cd {ui_project_home_path} $ gem update --system $ gem install compass $ npm install -g bower grunt-cli $ npm install $ bower install
Vagrant
Vagrant.configure("2") do |config| config.vm.box = "ubuntu/trusty64" config.vm.provision :shell, path: "for-vagrant/setup.sh" config.vm.provision :shell, path: "for-vagrant/startup.sh", run: "always" config.vm.network :forwarded_port, host: 8080, guest: 8080 config.vm.network :forwarded_port, host: 9000, guest: 9000 config.vm.network :forwarded_port, host: 9001, guest: 9001 config.vm.network :forwarded_port, host: 3306, guest: 3306 config.vm.network :forwarded_port, host: 35729, guest: 35729 config.vm.boot_timeout=3000 # config.ssh.insert_key = true # config.vm.synced_folder '.', '/vagrant', disabled: true config.vm.provider :virtualbox do |vb| # vb.gui = true # Use VBoxManage to customize the VM. For example to change memory: vb.customize ["modifyvm", :id, "--name", "jhipster-devbox"] vb.customize ["modifyvm", :id, "--memory", "4096"] vb.customize ["modifyvm", :id, "--vram", 64] vb.customize ["modifyvm", :id, "--accelerate3d", "on"] vb.customize ['modifyvm', :id, '--clipboard', 'bidirectional'] vb.customize ['modifyvm', :id, '--draganddrop', 'bidirectional'] end end
setup.sh
#!/bin/bash # update the system apt-get update apt-get upgrade export LANGUAGE='en_US.UTF-8' export LANG='en_US.UTF-8' export LC_ALL='en_US.UTF-8' locale-gen en_US.UTF-8 dpkg-reconfigure locales # install utilities apt-get -y install vim git zip bzip2 fontconfig curl language-pack-en # install Java 8 echo 'deb http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main' >> /etc/apt/sources.list echo 'deb-src http://ppa.launchpad.net/webupd8team/java/ubuntu trusty main' >> /etc/apt/sources.list apt-key adv --keyserver keyserver.ubuntu.com --recv-keys C2518248EEA14886 apt-get update echo oracle-java-installer shared/accepted-oracle-license-v1-1 select true | sudo /usr/bin/debconf-set-selections apt-get install -y --force-yes oracle-java8-installer update-java-alternatives -s java-8-oracle # install rbenv apt-get install -y autoconf bison build-essential libssl-dev libyaml-dev libreadline6 libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm3 libgdbm-dev sleep 3 cd ~/ echo pwd git clone git://github.com/sstephenson/rbenv.git /root/.rbenv sleep 3 echo 'export PATH="/root/.rbenv/bin:$PATH"' >> ~/.bashrc echo 'eval "$(rbenv init -)"' >> ~/.bashrc export PATH="/root/.rbenv/bin:$PATH" eval "$(rbenv init -)" sleep 3 git clone git://github.com/sstephenson/ruby-build.git /root/.rbenv/plugins/ruby-build echo 'export PATH="/root/.rbenv/plugins/ruby-build/bin:$PATH"' >> ~/.bashrc export PATH="/root/.rbenv/plugins/ruby-build/bin:$PATH" sleep 3 source ~/.bashrc sleep 3 curl -fsSL https://gist.github.com/LeonB/10503374/raw | rbenv install --patch 2.0.0-p451 /root/.rbenv/bin/rbenv rehash /root/.rbenv/bin/rbenv global 2.0.0-p451 # install node.js curl -sL https://deb.nodesource.com/setup_4.x | bash - apt-get install -y nodejs unzip python g++ # update npm npm install -g npm # install yeoman grunt bower gulp npm install -g yo bower grunt-cli gem update --system gem install compass cd /vagrant/bins_ui bower install npm install # install Docker curl -sL https://get.docker.io/ | sh # install docker compose curl -L https://github.com/docker/compose/releases/download/1.8.1/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose chmod +x /usr/local/bin/docker-compose # configure docker group (docker commands can be launched without sudo) usermod -aG docker vagrant # clean the box apt-get -y autoclean apt-get -y clean apt-get -y autoremove dd if=/dev/zero of=/EMPTY bs=1M > /dev/null 2>&1 rm -f /EMPTY # run db, tomcat, grunt serve cd /vagrant docker-compose up -d cd /vagrant/bins_ui grunt serve
결론!
이럴때 써보니 확실히 좋더라?
- 프로젝트에 새로운 개발자가 투입되어서 개발환경을 셋팅해 주어야 할 때!
- 중국에 출장을 갔는데 중국 개발자들과 같이 협업해서 개발해야 될 때
- 인수인계 해주어야 할 때
- 셋팅보다 비즈니스 로직에 집중해야 할 때
Docker-compose VS Vagrant
ㅇ 가벼운걸 원한다면 Docker-compose 를!
- 너무나도 잘 아시다시피 Docker 가 VM 에 비해서 가볍습니다. Single VM host 에 많은 application 을 집어넣고 돌리는 거라면 Vagrant 로 해도 상관없지만 여러개의 VM host 가 떠야 한다면... 이렇게 띄웠을때 맥북이 이륙하는 소리가 들린다는.... +_+
ㅇ 개발환경에서의 셋팅을 Deploy 셋팅에서도 동일하게 써먹고 싶은 경우
ㅇ 실행시킨 application에 IP:port 로 직접 접근해야 한다면 Vagrant 를!
... ... config.vm.define "hdnode01" do |hdnode| hdnode.vm.box = "alonsodomin/ubuntu-trusty64-java8" hdnode.vm.network "private_network", ip: "10.x.x.x", :netmask => '255.255.255.0', :bridge => 'en0' hdnode.vm.provision "shell", inline: <<-SHELL echo HI ## 실행 시키고 싶은 명령어!! SHELL hdnode.vm.provider "virtualbox" do |vb| vb.memory = "256" end end ... ...
➜ ~ ifconfig lo0: flags=8049mtu 16384 ... ... ... ... en0: flags=8863 mtu 1500 ... ...
그러면 Proxy Server 에 172.1.1.2:9000 으로 쏘면 10.10.10.2:xxxx (
DataNode 주소 및 포트 ) 로 proxy 를 겁니다.
그러니까 예를 들자면
hdfs://username@172.1.1.2:9000/user/username/app/file/file1.json
뭐 이런식으로 호출을 한다는 거죠. 그런데 Hadoop 은 마스터 Node 에게 file 경로를 주면 master 노드가 해당 파일을 저장하고 있는 slave 파일의 위치를 다시 전송해 줍니다.
(참고 : http://choong0121.tistory.com/entry/Hadoop-File-SystemHDFS )
그럼 만약 파일이 10.10.10.3에 있다고 가정하면 개발존에 있는 hadoop 클라이언트는 10.10.10.3에 해당 파일이 있음을 알게 되고 10.10.10.3:50010 ( 실제 파일이 존재하는 DataNode 주소 및 포트, Hadoop 의 기본 포트가 50010 이다. 설정마다 다른 포트값이 될 수도 있습니다.) 에 접근하려 하지만!!!
Fail.....
자료 출처 & 인용
아래는 회사에서 발표한 자료 입니다 :)
'Docker' 카테고리의 다른 글
[특집] container orchestration 쿠버네티스(Kubernetes) ( 쿠베르네테스 ) (0) | 2016.09.07 |
---|---|
2. Docker 를 이용해서 MySQL 버전별로 설치하기 (0) | 2016.06.22 |
1. Docker 란? - 장점 위주로! (0) | 2016.06.22 |
0. Docker 설치하기 (0) | 2016.06.22 |