Translate

2020년 4월 1일 수요일

[Spring Boot Admin] WAS 구동 시 발생하는 'InstanceAlreadyExistsException: com.zaxxer.hikari:name=dataSource,type=HikariDataSource' 에러




Spring Boot 2.x 사용



문제

WAS 구동 시 아래와 같은 에러메시지가 발생하며 웹페이지가 뜨지 않았다.


2020-04-01 18:53:09.673  INFO 19792 --- [com-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1321 ms
2020-04-01 18:53:10.219  INFO 19792 --- [com-startStop-1] o.s.b.a.e.web.ServletEndpointRegistrar   : Registered '/actuator/jolokia' to jolokia-actuator-endpoint
2020-04-01 18:53:10.854  INFO 19792 --- [com-startStop-1] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2020-04-01 18:53:10.930  INFO 19792 --- [com-startStop-1] o.s.b.a.w.s.WelcomePageHandlerMapping    : Adding welcome page template: index
2020-04-01 18:53:11.372  INFO 19792 --- [com-startStop-1] o.s.s.c.ThreadPoolTaskScheduler          : Initializing ExecutorService
2020-04-01 18:53:11.489  INFO 19792 --- [com-startStop-1] o.s.b.a.e.web.EndpointLinksResolver      : Exposing 16 endpoint(s) beneath base path '/actuator'
2020-04-01 18:53:11.544  INFO 19792 --- [com-startStop-1] ConditionEvaluationReportLoggingListener :

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-04-01 18:53:11.549 ERROR 19792 --- [com-startStop-1] o.s.boot.SpringApplication               : Application run failed

org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [HikariDataSource (null)] with key 'dataSource'; nested exception is javax.management.InstanceAlreadyExistsException: com.zaxxer.hikari:name=dataSource,type=HikariDataSource
        at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:626) ~[spring-context-5.1.14.RELEASE.jar:5.1.14.RELEASE]
        at org.springframework.jmx.export.MBeanExporter.lambda$registerBeans$2(MBeanExporter.java:552) ~[spring-context-5.1.14.RELEASE.jar:5.1.14.RELEASE]
        at java.util.HashMap.forEach(HashMap.java:1289) ~[na:1.8.0_241]
        at org.springframework.jmx.export.MBeanExporter.registerBeans(MBeanExporter.java:552) ~[spring-context-5.1.14.RELEASE.jar:5.1.14.RELEASE]
        at org.springframework.jmx.export.MBeanExporter.afterSingletonsInstantiated(MBeanExporter.java:435) ~[spring-context-5.1.14.RELEASE.jar:5.1.14.RELEASE]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:864) ~[spring-beans-5.1.14.RELEASE.jar:5.1.14.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877) ~[spring-context-5.1.14.RELEASE.jar:5.1.14.RELEASE]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) ~[spring-context-5.1.14.RELEASE.jar:5.1.14.RELEASE]
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141) ~[spring-boot-2.1.13.RELEASE.jar:2.1.13.RELEASE]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:744) ~[spring-boot-2.1.13.RELEASE.jar:2.1.13.RELEASE]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:391) ~[spring-boot-2.1.13.RELEASE.jar:2.1.13.RELEASE]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) ~[spring-boot-2.1.13.RELEASE.jar:2.1.13.RELEASE]
        at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:151) [spring-boot-2.1.13.RELEASE.jar:2.1.13.RELEASE]
        at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:131) [spring-boot-2.1.13.RELEASE.jar:2.1.13.RELEASE]
        at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:91) [spring-boot-2.1.13.RELEASE.jar:2.1.13.RELEASE]
        at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:172) [spring-web-5.1.14.RELEASE.jar:5.1.14.RELEASE]
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5154) [catalina.jar:8.5.51]
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183) [catalina.jar:8.5.51]
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:743) [catalina.jar:8.5.51]
        at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:719) [catalina.jar:8.5.51]
        at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:705) [catalina.jar:8.5.51]
        at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:970) [catalina.jar:8.5.51]
        at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1841) [catalina.jar:8.5.51]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_241]
        at java.util.concurrent.FutureTask.run(FutureTask.java:266) [na:1.8.0_241]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_241]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_241]
        at java.lang.Thread.run(Thread.java:748) [na:1.8.0_241]
Caused by: javax.management.InstanceAlreadyExistsException: com.zaxxer.hikari:name=dataSource,type=HikariDataSource
        at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:437) ~[na:1.8.0_241]
        at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(DefaultMBeanServerInterceptor.java:1898) ~[na:1.8.0_241]
        at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:966) ~[na:1.8.0_241]
        at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:900) ~[na:1.8.0_241]
        at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:324) ~[na:1.8.0_241]
        at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522) ~[na:1.8.0_241]
        at org.springframework.jmx.support.MBeanRegistrationSupport.doRegister(MBeanRegistrationSupport.java:138) ~[spring-context-5.1.14.RELEASE.jar:5.1.14.RELEASE]
        at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:672) ~[spring-context-5.1.14.RELEASE.jar:5.1.14.RELEASE]
        at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:616) ~[spring-context-5.1.14.RELEASE.jar:5.1.14.RELEASE]
        ... 27 common frames omitted

2020-04-01 18:53:11.551  WARN 19792 --- [com-startStop-1] o.s.b.f.support.DisposableBeanAdapter    : Invocation of destroy method failed on bean with name 'tomcatMetricsBinder': java.lang.NullPointerException
2020-04-01 18:53:11.552  INFO 19792 --- [com-startStop-1] o.s.s.c.ThreadPoolTaskScheduler          : Shutting down ExecutorService
2020-04-01 18:53:11.553  INFO 19792 --- [com-startStop-1] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
01-Apr-2020 18:53:11.555 SEVERE [video.aquapick-event.com-startStop-1] org.apache.catalina.core.ContainerBase.addChildInternal ContainerBase.addChild: start:
        org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[video.aquapick-event.com].StandardContext[]]
                at org.apache.catalina.util.LifecycleBase.handleSubClassException(LifecycleBase.java:440)
                at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:198)
                at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:743)
                at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:719)
                at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:705)
                at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:970)
                at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1841)
                at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
                at java.util.concurrent.FutureTask.run(FutureTask.java:266)
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
                at java.lang.Thread.run(Thread.java:748)
        Caused by: org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [HikariDataSource (null)] with key 'dataSource'; nested exception is javax.management.InstanceAlreadyExistsException: com.zaxxer.hikari:name=dataSource,type=HikariDataSource
                at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:626)
                at org.springframework.jmx.export.MBeanExporter.lambda$registerBeans$2(MBeanExporter.java:552)
                at java.util.HashMap.forEach(HashMap.java:1289)
                at org.springframework.jmx.export.MBeanExporter.registerBeans(MBeanExporter.java:552)
                at org.springframework.jmx.export.MBeanExporter.afterSingletonsInstantiated(MBeanExporter.java:435)
                at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:864)
                at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877)
                at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
                at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
                at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:744)
                at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:391)
                at org.springframework.boot.SpringApplication.run(SpringApplication.java:312)
                at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.run(SpringBootServletInitializer.java:151)
                at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.createRootApplicationContext(SpringBootServletInitializer.java:131)
                at org.springframework.boot.web.servlet.support.SpringBootServletInitializer.onStartup(SpringBootServletInitializer.java:91)
                at org.springframework.web.SpringServletContainerInitializer.onStartup(SpringServletContainerInitializer.java:172)
                at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5154)
                at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
                ... 10 more
        Caused by: javax.management.InstanceAlreadyExistsException: com.zaxxer.hikari:name=dataSource,type=HikariDataSource
                at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:437)
                at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(DefaultMBeanServerInterceptor.java:1898)
                at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:966)
                at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:900)
                at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:324)
                at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522)
                at org.springframework.jmx.support.MBeanRegistrationSupport.doRegister(MBeanRegistrationSupport.java:138)
                at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:672)
                at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:616)
                ... 27 more
01-Apr-2020 18:53:11.562 SEVERE [video.aquapick-event.com-startStop-1] org.apache.catalina.startup.HostConfig.deployWAR Error deploying web application archive [/home/1004lucifer/apps/apache-tomcat-8.5.51/webapps/urban/event/ROOT.war]
        java.lang.IllegalStateException: ContainerBase.addChild: start: org.apache.catalina.LifecycleException: Failed to start component [StandardEngine[Catalina].StandardHost[video.aquapick-event.com].StandardContext[]]
                at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:747)
                at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:719)
                at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:705)
                at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:970)
                at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1841)
                at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
                at java.util.concurrent.FutureTask.run(FutureTask.java:266)
                at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
                at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
                at java.lang.Thread.run(Thread.java:748)
01-Apr-2020 18:53:11.563 INFO [video.aquapick-event.com-startStop-1] org.apache.catalina.startup.HostConfig.deployWAR Deployment of web application archive [/home/1004lucifer/apps/apache-tomcat-8.5.51/webapps/urban/event/ROOT.war] has finished in [5,277] ms
01-Apr-2020 18:53:11.564 WARNING [main] org.apache.catalina.mapper.MapperListener.findDefaultHost Unknown default host [localhost] for service [StandardService[Catalina]]. Tomcat will not be able process HTTP/1.0 requests that do not specify a host name.
01-Apr-2020 18:53:11.569 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["http-nio-8080"]
01-Apr-2020 18:53:11.585 INFO [main] org.apache.coyote.AbstractProtocol.start Starting ProtocolHandler ["https-jsse-nio-8443"]
01-Apr-2020 18:53:11.588 INFO [main] org.apache.catalina.startup.Catalina.start Server startup in 16541 ms






원인

스택오버플로우 확인 시 jmx 충돌로 인해 발생하는 문제로 보여졌다.


그러고보니 문제가 발생한 시점이..

1개의 서버에 아래와 같이 두개의 애플리케이션이 올라가 있는 상태에서..
 - Spring Boot Admin (Server)
 - Spring Boot Admin (Client)

신규 Spring Boot Admin (Client) 를 추가하고 바로 발생했다.



1004lucifer


해결방법

JMX 이름을 다르게해서 다시 배포를 하니 정상적으로 동작되는 것을 확인 할 수 있었다.
(Spring Boot 2.1.13 기준)


spring:
  jmx:
    unique-names: true
management:
  endpoints:
    jmx:
      domain: co.kr.1004lucifer





참고:
 - https://stackoverflow.com/questions/51798003/javax-management-instancealreadyexistsexception-com-zaxxer-hikariname-datasour/51798043


2020년 3월 11일 수요일

[Let's Encrypt] 우분투 Tomcat 에 무료 SSL (와일드카드)인증서 설치방법





톰캣에 설치할 무료 SSL인증서를 알아보니 대부분 3개월 기간으로만 제공을 하는데..
Let's Encrypt에서는 Cron을 이용하여 자동연장이 가능하기에 작업을 시작했다.

공식 사이트: https://letsencrypt.org/ko/


실습환경: Ubuntu 18.04


1. certbot 설치


ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$ certbot
# certbot이 설치되지 않은상태
Command 'certbot' not found, but can be installed with:

sudo apt install certbot

ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$ sudo apt-get update
Hit:1 http://ap-seoul-1-ad-1.clouds.archive.ubuntu.com/ubuntu bionic InRelease
Get:2 http://security.ubuntu.com/ubuntu bionic-security InRelease [88.7 kB]
Hit:3 http://ppa.launchpad.net/certbot/certbot/ubuntu bionic InRelease
Get:4 http://ap-seoul-1-ad-1.clouds.archive.ubuntu.com/ubuntu bionic-updates InRelease [88.7 kB]
Get:5 http://ap-seoul-1-ad-1.clouds.archive.ubuntu.com/ubuntu bionic-backports InRelease [74.6 kB]
Get:6 http://ap-seoul-1-ad-1.clouds.archive.ubuntu.com/ubuntu bionic-updates/main amd64 Packages [871 kB]
Get:7 http://ap-seoul-1-ad-1.clouds.archive.ubuntu.com/ubuntu bionic-updates/universe amd64 Packages [1055 kB]
Get:8 http://ap-seoul-1-ad-1.clouds.archive.ubuntu.com/ubuntu bionic-updates/universe Translation-en [326 kB]
Fetched 2505 kB in 3s (798 kB/s)
Reading package lists... Done
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$ sudo apt-get install software-properties-common
Reading package lists... Done
Building dependency tree
Reading state information... Done
software-properties-common is already the newest version (0.96.24.32.12).
The following package was automatically installed and is no longer required:
  grub-pc-bin
Use 'sudo apt autoremove' to remove it.
0 upgraded, 0 newly installed, 0 to remove and 42 not upgraded.
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$ sudo add-apt-repository ppa:certbot/certbot
 This is the PPA for packages prepared by Debian Let's Encrypt Team and backported for Ubuntu.

Note: Packages are only provided for currently supported Ubuntu releases.
 More info: https://launchpad.net/~certbot/+archive/ubuntu/certbot
Press [ENTER] to continue or Ctrl-c to cancel adding it.

Hit:1 http://security.ubuntu.com/ubuntu bionic-security InRelease
Hit:2 http://ppa.launchpad.net/certbot/certbot/ubuntu bionic InRelease
Hit:3 http://ap-seoul-1-ad-1.clouds.archive.ubuntu.com/ubuntu bionic InRelease
Hit:4 http://ap-seoul-1-ad-1.clouds.archive.ubuntu.com/ubuntu bionic-updates InRelease
Hit:5 http://ap-seoul-1-ad-1.clouds.archive.ubuntu.com/ubuntu bionic-backports InRelease
Reading package lists... Done
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$ sudo apt-get install certbot
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following package was automatically installed and is no longer required:
  grub-pc-bin
Use 'sudo apt autoremove' to remove it.
The following additional packages will be installed:
  python3-acme python3-certbot python3-configargparse python3-future python3-icu python3-josepy python3-mock python3-ndg-httpsclient python3-parsedatetime python3-pbr python3-requests-toolbelt python3-rfc3339 python3-tz
  python3-zope.component python3-zope.event python3-zope.hookable
Suggested packages:
  python3-certbot-apache python3-certbot-nginx python-certbot-doc python-acme-doc python-future-doc python-mock-doc
The following NEW packages will be installed:
  certbot python3-acme python3-certbot python3-configargparse python3-future python3-icu python3-josepy python3-mock python3-ndg-httpsclient python3-parsedatetime python3-pbr python3-requests-toolbelt python3-rfc3339 python3-tz
  python3-zope.component python3-zope.event python3-zope.hookable
0 upgraded, 17 newly installed, 0 to remove and 42 not upgraded.
Need to get 1113 kB of archives.
After this operation, 5884 kB of additional disk space will be used.
Do you want to continue? [Y/n] y
Get:1 http://ap-seoul-1-ad-1.clouds.archive.ubuntu.com/ubuntu bionic/main amd64 python3-pbr all 3.1.1-3ubuntu3 [53.8 kB]
Get:2 http://ppa.launchpad.net/certbot/certbot/ubuntu bionic/main amd64 python3-josepy all 1.1.0-2+ubuntu18.04.1+certbot+1 [27.8 kB]

  생략...

Setting up python3-josepy (1.1.0-2+ubuntu18.04.1+certbot+1) ...
Setting up python3-tz (2018.3-2) ...
Setting up python3-parsedatetime (2.4-3+ubuntu18.04.1+certbot+3) ...
Setting up python3-rfc3339 (1.0-4) ...
Setting up python3-zope.component (4.3.0-1+ubuntu18.04.1+certbot+3) ...
Setting up python3-acme (0.31.0-2+ubuntu18.04.3+certbot+2) ...
Setting up python3-certbot (0.31.0-1+ubuntu18.04.1+certbot+1) ...
Setting up certbot (0.31.0-1+ubuntu18.04.1+certbot+1) ...
Created symlink /etc/systemd/system/timers.target.wants/certbot.timer → /lib/systemd/system/certbot.timer.
certbot.service is a disabled or a static unit, not starting it.
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$ certbot
#정상적으로 설치완료
The following error was encountered:
[Errno 13] Permission denied: '/var/log/letsencrypt'
Either run as root, or set --config-dir, --work-dir, and --logs-dir to writeable paths.
ubuntu@instance-1004lucifer:~$






2. 인증서 생성


ubuntu@instance-1004lucifer:~$ sudo certbot certonly --manual --preferred-challenges dns -d "1004lucifer.co.kr" -d "*.1004lucifer.co.kr"
Saving debug log to /var/log/letsencrypt/letsencrypt.log
Plugins selected: Authenticator manual, Installer None
Obtaining a new certificate
Performing the following challenges:
dns-01 challenge for 1004lucifer.co.kr

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NOTE: The IP of this machine will be publicly logged as having requested this
certificate. If you're running certbot in manual mode on a machine that is not
your server, please ensure you're okay with that.

Are you OK with your IP being logged?
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
(Y)es/(N)o: y

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Please deploy a DNS TXT record under the name
_acme-challenge.1004lucifer.co.kr with the following value:

M7dc7nmfVKAXWdDZ5b2H1vIw8iAD82FKdfPGAi0YOCA

Before continuing, verify the record is deployed.
# 이부분에서 DNS의 TXT에 해당 도메인과 문자열을 넣어주고 잠시 후 엔터를 입력한다.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Press Enter to Continue
Waiting for verification...
Cleaning up challenges

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/1004lucifer.co.kr/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/1004lucifer.co.kr/privkey.pem
   Your cert will expire on 2020-06-08. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot
   again. To non-interactively renew *all* of your certificates, run
   "certbot renew"
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le

ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$ ll /etc/letsencrypt/
total 40
drwxr-xr-x  9 root root 4096 Mar 11 17:12 ./
drwxr-xr-x 97 root root 4096 Mar 11 19:57 ../
drwx------  3 root root 4096 Mar  9 20:16 accounts/
drwx------  3 root root 4096 Mar 10 13:47 archive/
-rw-r--r--  1 root root  121 Feb 10  2019 cli.ini
drwxr-xr-x  2 root root 4096 Mar 11 16:36 csr/
drwx------  2 root root 4096 Mar 11 16:36 keys/
drwx------  3 root root 4096 Mar 10 13:47 live/
drwxr-xr-x  2 root root 4096 Mar 11 16:36 renewal/
drwxr-xr-x  5 root root 4096 Mar  9 20:16 renewal-hooks/
ubuntu@instance-1004lucifer:~$
# 인증서 디렉토리 root 외 사용자에게 읽기권한 부여
ubuntu@instance-1004lucifer:~$ sudo chmod 755 /etc/letsencrypt/live/
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$ ll /etc/letsencrypt/
total 40
drwxr-xr-x  9 root root 4096 Mar 11 17:12 ./
drwxr-xr-x 97 root root 4096 Mar 11 19:57 ../
drwx------  3 root root 4096 Mar  9 20:16 accounts/
drwx------  3 root root 4096 Mar 10 13:47 archive/
-rw-r--r--  1 root root  121 Feb 10  2019 cli.ini
drwxr-xr-x  2 root root 4096 Mar 11 16:36 csr/
drwx------  2 root root 4096 Mar 11 16:36 keys/
drwx--x--x  3  711 root 4096 Mar 10 13:47 live/
drwxr-xr-x  2 root root 4096 Mar 11 16:36 renewal/
drwxr-xr-x  5 root root 4096 Mar  9 20:16 renewal-hooks/
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$ ll /etc/letsencrypt/live/1004lucifer.co.kr/
total 28
drwxr-xr-x 2 root root 4096 Mar 11 16:36 ./
drwxr-xr-x 3  755 root 4096 Mar 10 13:47 ../
-rw-r--r-- 1 root root  692 Mar 10 13:47 README
lrwxrwxrwx 1 root root   41 Mar 11 16:36 cert.pem -> ../../archive/1004lucifer.co.kr/cert2.pem
lrwxrwxrwx 1 root root   42 Mar 11 16:36 chain.pem -> ../../archive/1004lucifer.co.kr/chain2.pem
lrwxrwxrwx 1 root root   46 Mar 11 16:36 fullchain.pem -> ../../archive/1004lucifer.co.kr/fullchain2.pem
lrwxrwxrwx 1 root root   44 Mar 11 16:36 privkey.pem -> ../../archive/1004lucifer.co.kr/privkey2.pem

ubuntu@instance-1004lucifer:~$



Cafe24에서 다음과 같이 작업을 했다.
(PS. 처음에 호스트명에 입력란이 보여지지 않아 Cafe24에 문의를 해보니 첫 등록 시 상담게시판을 이용하여 등록요청을 후 한번 등록이 되면 그 이후에 입력란이 보여진다.)






3. 톰캣용 인증서 생성


ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$ sudo bash
root@instance-1004lucifer:~#
root@instance-1004lucifer:~#
root@instance-1004lucifer:~# cd /etc/letsencrypt/live/1004lucifer.co.kr/
root@instance-1004lucifer:/etc/letsencrypt/live/1004lucifer.co.kr#
root@instance-1004lucifer:/etc/letsencrypt/live/1004lucifer.co.kr#
root@instance-1004lucifer:/etc/letsencrypt/live/1004lucifer.co.kr# openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out cert_and_key.p12 -CAfile chain.pem -caname root -passout pass:password -name root
root@instance-1004lucifer:/etc/letsencrypt/live/1004lucifer.co.kr#
root@instance-1004lucifer:/etc/letsencrypt/live/1004lucifer.co.kr# ll
total 20
drwxr-xr-x 2 root root 4096 Mar 11 21:42 ./
drwxr-xr-x 3  755 root 4096 Mar 10 13:47 ../
-rw-r--r-- 1 root root  692 Mar 10 13:47 README
lrwxrwxrwx 1 root root   41 Mar 11 16:36 cert.pem -> ../../archive/1004lucifer.co.kr/cert2.pem
-rw------- 1 root root 4294 Mar 11 21:42 cert_and_key.p12
lrwxrwxrwx 1 root root   42 Mar 11 16:36 chain.pem -> ../../archive/1004lucifer.co.kr/chain2.pem
lrwxrwxrwx 1 root root   46 Mar 11 16:36 fullchain.pem -> ../../archive/1004lucifer.co.kr/fullchain2.pem
lrwxrwxrwx 1 root root   44 Mar 11 16:36 privkey.pem -> ../../archive/1004lucifer.co.kr/privkey2.pem
root@instance-1004lucifer:/etc/letsencrypt/live/1004lucifer.co.kr#
root@instance-1004lucifer:/etc/letsencrypt/live/1004lucifer.co.kr#
root@instance-1004lucifer:/etc/letsencrypt/live/1004lucifer.co.kr# keytool -delete -alias root -keystore keyStore.jks -importkeystore -srcstorepass password -destkeystore keyStore.jks -srckeystore cert_and_key.p12 -srcstoretype PKCS12 -storepass password
Importing keystore cert_and_key.p12 to keyStore.jks...
Entry for alias root successfully imported.
Import command completed:  1 entries successfully imported, 0 entries failed or cancelled

Warning:
The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore keyStore.jks -destkeystore keyStore.jks -deststoretype pkcs12".
root@instance-1004lucifer:/etc/letsencrypt/live/1004lucifer.co.kr#
root@instance-1004lucifer:/etc/letsencrypt/live/1004lucifer.co.kr#
root@instance-1004lucifer:/etc/letsencrypt/live/1004lucifer.co.kr# ll
total 24
drwxr-xr-x 2 root root 4096 Mar 11 21:42 ./
drwxr-xr-x 3  755 root 4096 Mar 10 13:47 ../
-rw-r--r-- 1 root root  692 Mar 10 13:47 README
lrwxrwxrwx 1 root root   41 Mar 11 16:36 cert.pem -> ../../archive/1004lucifer.co.kr/cert2.pem
-rw------- 1 root root 4294 Mar 11 21:42 cert_and_key.p12
lrwxrwxrwx 1 root root   42 Mar 11 16:36 chain.pem -> ../../archive/1004lucifer.co.kr/chain2.pem
lrwxrwxrwx 1 root root   46 Mar 11 16:36 fullchain.pem -> ../../archive/1004lucifer.co.kr/fullchain2.pem
-rw-r--r-- 1 root root 3932 Mar 11 21:42 keyStore.jks
lrwxrwxrwx 1 root root   44 Mar 11 16:36 privkey.pem -> ../../archive/1004lucifer.co.kr/privkey2.pem
root@instance-1004lucifer:/etc/letsencrypt/live/1004lucifer.co.kr#






4. 톰캣에 인증서 연동


ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$ cat apps/apache-tomcat-8.5.51/conf/server.xml
<?xml version="1.0" encoding="UTF-8"?>

    생략...

    <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
               maxThreads="150" SSLEnabled="true">
        <SSLHostConfig>
        <Certificate certificateKeystoreFile="/etc/letsencrypt/live/1004lucifer.co.kr/keyStore.jks"
                 certificateKeystorePassword="password"
                         type="RSA" />
        </SSLHostConfig>
    </Connector>

    생략...

</Server>
ubuntu@instance-1004lucifer:~$


여기까지 작업 후 톰캣을 재구동하면 HTTPS 접속이 될 것이다.


아래와 같이 사이트 접속 후 인증서가 적용됨을 확인 할 수 있다.












4. 인증서 자동갱신 셋팅

Let's Encrypt 의 인증서는 3달마다 갱신을 해줘야 한다.
리눅스 명령어를 이용해 인증서를 발급받았으니..
쉘을 만들어서 주기적으로 자동갱신을 하도록 만들어 주자.

정상적으로 갱신되는지 여부 확인해보지 못함.
추후 확인예정


ubuntu@instance-1004lucifer:~$
ubuntu@instance-1004lucifer:~$ sudo bash
root@instance-1004lucifer:~#
root@instance-1004lucifer:~#
root@instance-1004lucifer:~#
# 스크립트를 생성한다.
root@instance-1004lucifer:~# cat > /etc/letsencrypt/live/1004lucifer.co.kr/extend.sh
#!/bin/bash

cd /etc/letsencrypt/live/1004lucifer.co.kr/

certbot renew --quiet

openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out cert_and_key.p12 -CAfile chain.pem -caname root -passout pass:password -name root

keytool -delete -alias root -storepass password -keystore keyStore.jks

keytool -importkeystore -srcstorepass password -destkeystore keyStore.jks -srckeystore cert_and_key.p12 -srcstoretype PKCS12 -storepass password

^C  (Ctrl + C)
root@instance-1004lucifer:~#
root@instance-1004lucifer:~#
root@instance-1004lucifer:~#
root@instance-1004lucifer:~# cat /etc/letsencrypt/live/1004lucifer.co.kr/extend.sh
#!/bin/bash

cd /etc/letsencrypt/live/1004lucifer.co.kr/

certbot renew --quiet

openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out cert_and_key.p12 -CAfile chain.pem -caname root -passout pass:password -name root

keytool -delete -alias root -storepass password -keystore keyStore.jks


keytool -importkeystore -srcstorepass password -destkeystore keyStore.jks -srckeystore cert_and_key.p12 -srcstoretype PKCS12 -storepass password

root@instance-1004lucifer:~#
root@instance-1004lucifer:~#
root@instance-1004lucifer:~#
# 크론에 스크립트를 등록해 준다.
root@instance-1004lucifer:~# crontab -e
crontab: installing new crontab
root@instance-1004lucifer:~#
root@instance-1004lucifer:~#
root@instance-1004lucifer:~# crontab -l
# Edit this file to introduce tasks to be run by cron.
#
# Each task to run has to be defined through a single line
# indicating with different fields when the task will be run
# and what command to run for the task
#
# To define the time you can provide concrete values for
# minute (m), hour (h), day of month (dom), month (mon),
# and day of week (dow) or use '*' in these fields (for 'any').#
# Notice that tasks will be started based on the cron's system
# daemon's notion of time and timezones.
#
# Output of the crontab jobs (including errors) is sent through
# email to the user the crontab file belongs to (unless redirected).
#
# For example, you can run a backup of all your user accounts
# at 5 a.m every week with:
# 0 5 * * 1 tar -zcf /var/backups/home.tgz /home/
#
# For more information see the manual pages of crontab(5) and cron(8)
#
# m h  dom mon dow   command

# 1004lucifer
# LetsEncrypt SSL
0 0 1 * * /etc/letsencrypt/live/1004lucifer.co.kr/extend.sh
root@instance-1004lucifer:~#
root@instance-1004lucifer:~#



Ubuntu, 우분투, Tomcat, 톰캣, SSL, https, 인증서, 와일드카드, wildcard, 생성, 설치


참고
 - https://hiseon.me/server/letsencrypt-wildcard-certificate/
 - https://partnerjun.tistory.com/60


2020년 3월 9일 월요일

[PowerMockup] PPT 기획서 작성 플러그인 - 파워목업




이번에 PPT 형식의 UI기획서를 작성해야 하는일이 생겼다.

와이어프레임을 바로 만들까 했지만 그래도 그전에 다른 멤버들과 공유할 수 있는 기획서를 우선 작성을 하기로 결정을 했다.


https://www.powermockup.com/

파워목업 사이트에서 프로그램을 다운받아 다음과 같이 설치를 했다.







설치 후 실행을 누르면 아래와 같이 PPT가 실행되며 오른쪽에 파워목업이 보여지게 된다.






Download More 버튼을 클릭하면 아래와 같이 추가 요소들을 다운받을 수 있다.






아래와 같이 해당 요소를 드래그앤드롭 형식으로 이용할 수 있다.




각각의 요소를 확인해보니 모두 하나하나 수작업으로 만들고 그룹으로 묶은 것으로 보여진다.
홈페이지에 보면 800개 이상의 요소가 있다고 하는데 작업자들의 고생이 눈에 훤히 보인다.


처음에 라이센스를 등록하기 전까지는 일부 요소만 사용이 가능한데 아쉬운 부분이다.
차라리 하루정도라도 전체적으로 사용해볼 수 있으면 괜찮을것 같은데 말이다..

지금 보고있는 이 블로그 포스팅과 같이 파워목업에 대한 포스팅 작성 후 이메일로 요청을 하게되면 1인 개인 라이센스를 무료로 받을 수 있다고 한다.


기획서 제작의 시간을 최소화 하면서 품질을 올릴 수 있다는데에서 파워목업은 꽤나 좋은 툴 이라고 생각이 든다.
이번기회를 통해 파워목업을 제대로 한번 써봐야겠다.

2020년 2월 27일 목요일

[Oracle] import 시 테이블 주석(comment)의 한글이 깨지는 경우





증상

 - 오라클에서 imp 명령어로 데이터 import 시 테이블 데이터의 한글은 정상적으로 나오지만 주석만 한글이 ??? 와 같이 깨져서 보여지는 경우
(exp, imp 서버 둘다 캐릭터셋은 동일하게 맞춘상황)

Table, 테이블, 주석, comment, 한글, 깨짐



해결방법
1004lucifer
- 아래와 같이 exp, imp 명령어 수행전 NLS_LANG 을 똑같이 맞춰준다.



[oracle@5cc21db1547a tmp]$ export NLS_LANG=AMERICAN_AMERICA.KO16MSWIN949
[oracle@5cc21db1547a tmp]$
[oracle@5cc21db1547a tmp]$ exp user/password@192.168.0.100/SID file=./data.dmp tables=\(AAAAAAAAAA,BBBBBBBB, ... ,ZZZZZZZZ\)

Export: Release 12.2.0.1.0 - Production on Thu Feb 27 14:37:48 2020

Copyright (c) 1982, 2017, Oracle and/or its affiliates.  All rights reserved.


Connected to: Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production
Export done in KO16MSWIN949 character set and UTF8 NCHAR character set

About to export specified tables via Conventional Path ...
. . exporting table                    AAAAAAAAAAA          1 rows exported
. . exporting table                     BBBBBBBBBB         78 rows exported
                          ...
. . exporting table                     ZZZZZZZZZZ          6 rows exported
Export terminated successfully without warnings.
[oracle@5cc21db1547a tmp]$

...
1004lucifer
[oracle@7b4cc751ef5c setup]$ export NLS_LANG=AMERICAN_AMERICA.KO16MSWIN949
[oracle@7b4cc751ef5c setup]$
[oracle@7b4cc751ef5c setup]$ imp user/password full=y file=/home/oracle/setup/data.dmp

Import: Release 12.2.0.1.0 - Production on Thu Feb 27 15:56:50 2020

Copyright (c) 1982, 2017, Oracle and/or its affiliates.  All rights reserved.


Connected to: Oracle Database 12c Enterprise Edition Release 12.2.0.1.0 - 64bit Production

Export file created by EXPORT:V12.02.00 via conventional path
import done in KO16MSWIN949 character set and AL16UTF16 NCHAR character set
export server uses UTF8 NCHAR character set (possible ncharset conversion)
IMP-00403:

Warning: This import generated a separate SQL file "import_sys" which contains DDL that failed due to a privilege issue.

. importing SID's objects into SID
. importing SID's objects into SID
. . importing table                  "AAAAAAAAAAA"          1 rows imported
. . importing table                   "BBBBBBBBBB"         78 rows imported
                             ...
. . importing table                   "ZZZZZZZZZZ"          6 rows imported
Import terminated successfully with warnings.
[oracle@7b4cc751ef5c setup]$ 




PS.
데이터는 문제가 없어서 그냥 둘까 하다가 혹시나 싶어서 위와같이 exp를 다시 수행해서 작업했더니 정상적으로 Table comment 가 보여졌다.



[IE] 개발자도구 - 디버거에서 소스가 보여지지 않는경우 해결방법




IE11

친구 PC의 익스플로러에서 개발자 도구에서 아래와 같이 디버거에서 소스가 보여지지 않는 상황이 발생했다.






아래와 같이 구분탭이 완전히 왼쪽으로 치우쳐져서 없어진걸로 보인거고..
실제로는 아래와 같이 마우스로 드래그하면 소스가 보여진다.
1004lucifer




참고
 - https://social.technet.microsoft.com/Forums/ie/en-US/38afdc33-21aa-47aa-a192-410ab3a92817/f12-debugger-on-ie-11-wont-display-source-any-more?forum=ieitprocurrentver



2020년 2월 9일 일요일

[Tomcat] Windows에서 로그 한글깨짐 원인과 해결 방법




테스트 환경
OS: Windows 10
비고: (Eclipse/IntelliJ) IDE를 사용하지 않고 톰캣을 자체적으로 구동한 상황





[ 증상 ]

 - 증상은 아래와 같이 두가지 종류가 있다. 환경에 따라 두개 모두 가지고 있을 수 있다.


1. 톰캣에서 자체적으로 남기는 로그의 한글이 깨짐
1004lucifer



2. 프로그램에서 남기는 로그의 한글이 깨짐
  (Windows10 환경에서 이클립스와 같은 IDE가 아닌 단독 톰캣의 경우에는 증상을 재현하지 못했다. 아래는 jsp에 pageEncoding을 지정하지 않았을경우..)







[ 원인 및 해결방법 ]


1. 톰캣에서 자체적으로 남기는 로그의 한글이 깨짐

* 좀 더 정확한 증상은 옛날 버전의 톰캣은 한글이 깨지지 않고 최신버전의 톰캣만 한글이 깨진다.


원인

* Windows10의 콘솔 인코딩과 톰캣에서 남기는 로그의 인코딩이 달라 문제가 발생함


  1) 톰캣 버전별 변경사항 확인
    - Tomcat7 기준 v7.0.92에서 '{_TOMCAT_HOME_}/conf/logging.properties' 설정파일에 인코딩 관련 설정이 추가되었다. (default:UTF-8)
   (https://tomcat.apache.org/tomcat-7.0-doc/changelog.html)
1004lucifer

  2) Tomcat의 logging.properties 파일에 인코딩 설정 추가된 버전 (버전별 ChangeLog확인)
    - Tomcat7:   v7.0.92 이상
    - Tomcat8.5: v8.5.36 이상
    - Tomcat9:   v9.0.14 이상
    - 톰캣 버전 v8.5.35 와 같이 위에 명시한 것보다 이전 버전이라면 해당 증상이 발생하지 않는다.
    - 그래서 톰캣 버전에 따라서 아무런 설정을 하지도 한글이 깨지는 사람이 있고 안깨지는 사람이 발생할수 있다.


  3) Windows10의 콘솔 인코딩 한국어 설정 확인
    - chcp 명령어 확인

    - 콘솔 속성 확인





해결방법

* Tomcat의 logging.properties 파일에 인코딩설정이 있는 톰캣을 사용하는 경우


  1) 톰캣의 마이너 버전을 다운그레이드 한다.
    - 위에서 설명했듯이 특정버전 이상에서만 증상이 발생하며 아래와 같이 해당 버전 이하로 구동 시 별다른 설정 없이 톰캣로그가 한글깨짐 없이 정상적으로 보여진다.
    - Tomcat7:   v7.0.91 이하
    - Tomcat8.5: v8.5.35 이하
    - Tomcat9:   v9.0.13 이하



  2) logging.properties 파일의 인코딩 설정을 UTF-8 => EUC-KR 로 변경해 준다.
1004lucifer

1catalina.org.apache.juli.FileHandler.level = FINE
1catalina.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
1catalina.org.apache.juli.FileHandler.prefix = catalina.
1catalina.org.apache.juli.AsyncFileHandler.encoding = EUC-KR

2localhost.org.apache.juli.FileHandler.level = FINE
2localhost.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
2localhost.org.apache.juli.FileHandler.prefix = localhost.
2localhost.org.apache.juli.AsyncFileHandler.encoding = EUC-KR

3manager.org.apache.juli.FileHandler.level = FINE
3manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
3manager.org.apache.juli.FileHandler.prefix = manager.
3manager.org.apache.juli.AsyncFileHandler.encoding = EUC-KR

4host-manager.org.apache.juli.FileHandler.level = FINE
4host-manager.org.apache.juli.FileHandler.directory = ${catalina.base}/logs
4host-manager.org.apache.juli.FileHandler.prefix = host-manager.
4host-manager.org.apache.juli.AsyncFileHandler.encoding = EUC-KR

java.util.logging.ConsoleHandler.level = FINE
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.ConsoleHandler.encoding = EUC-KR




  3) Windows 10 콘솔 기본 인코딩 설정을 변경해준다. (레지스트리를 변경하며 권장하지 않음)
    - 윈도우키+R: regedit 입력하여 레지스트리편집기 실행
    - 컴퓨터\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage 밑으로 스크롤해 OEMCP를 클릭하고, 값을 65001로 변경






2. 프로그램에서 남기는 로그의 한글이 깨짐

Windows10 에서 IDE 없이 단톡톰캣으로 증상 재현불가







PS. 후기

다른 블로그에 나와있지 않은 logging.properties 설정파일 방법을 알아낸건 우연히 같은 프로그램소스를 같은 Tomcat7 로 구동 시 한글이 깨지거나 깨지지 않는 증상을 발견한 것이 시발점이 되어 알아보게 되었다.
같은 Tomcat7 이었지만 마이너버전만 달랐다. 그래서 톰캣 마이너버전을 종류별로 받아서 테스트를 진행했었고 특정 버전 이상에서만 한글이 깨지는 것을 확인했었다.
ChangeLog 를 확인하고 나서야 왜 이런 증상이 발생을 했었고..

다른 블로그를 봤을 때 예전에는 -Dfile.encoding=UTF-8 밖에 없었는데 비교적 최근에 작성된 글에서는 레지스트리를 변경하라는 이야기가 나오는지 이해가 갔다.

그리고 startup.bat 파일을 수정하는 방법으로도 접근해 봤는데 'chcp 65001' 설정 후 catalina.bat 에 넘겨주는 인자를 start에서 run 으로 변경 시 톰캣 한글은 정상적으로 나오지만 프로그램 로그(System.out.print)가 콘솔에 찍히지 않아 위에 기술하지 못했다.
추후 원인을 알게되면 위에 세번째 방법으로 추가를 하려 한다.





참고
 - https://meyouus.tistory.com/12