반응형

최근에 Kubernetes에 어플리케이션을 올리다가 몇일간 맨붕 상태가 온 내용을 남겨두고자 한다. 

 

Kubernetes 클러스터에 my-test1 이라는 네임스페이스로 ingress, servcie, deployment 를 생성하였다. 

 

여기 까지는 문제가 없었는데 도메인을 설정하고 tls 를 설정하면서 문제가 발생했다.

 

1. test.com 이라는 도메인으로 사설 인증서 생성.

2. crt 파일과 key 파일을 이용해서 secret 생성

3. ingress 에 tls 설정에 host와 tls 를 설정.

 

위와같이 진행을 하고 접속을 해봤다. 

그런데 이상하게 브라우저에서 "주의요함" 부분을 클릭해보면 내가 만든 사설인증서의 도메인이 나오는게 아니라 Kubernetes의 Fake 인증서가 나왔다. 분명히 나는 인증서를 설정했는데..

 

이것때문에 원인을 찾느라 한참 고생했다.

 

결국 원인을 찾았는데 문제는 동일한 도메인을 사용하는 다른 ingress 들 때문이었다. 

 

내가 사용중인 네임스페이스의 ingress 를 생성하면 kube-system 에 있는 ingress-constroller 에 등록이 된다. 이때에 내가 설정한 어플리케이션 뿐만 아니라 다른 네임스페이스의 어플리케이션의 ingress 도 생성하면 동일하게 등록이 된다. 

 

이때에 중요한 점은 같은 도메인일 경우이다.

 

만약 내가 ingress 의 tls 설정을 아래와 같이 했다고 가정해보자

 

tls:
- hosts:
- test.com
secretName: my-test-secret

 

그런데 다른 어플리케이션에서 ingress 를 아래와 같이 설정을 했다.

 

tls:
- hosts:
- test.com

 

이럴 경우 아래쪽에 ingress 의 설정에 secret 이 없기때문에 Fake 인증서를 사용하게 된다. 아마도 순서에 영향을 받지 않나 싶다. 결과적으로 ingress 를 반영을 하게되면 kube-system의 ingress-controller 에 반영이 되고 결국 내부의 nginx.conf 파일에 반영이 되기 때문에 아마도 순서에 영향을 받을 것 같긴 하다. 

 

따라서 같은 도메인일 경우에는 namespace 별로 secret을 다 만들어서 같이 설정을 해두던지 아니면 하나의 ingress 에서만 secret 설정을 하고 나머지는 tls 설정을 삭제 해줘야 한다.

 

이것때문에 너무 시간도 많이 낭비했는데.. 역시 모르면 몸이 고생이다. ㅠㅠ

 

728x90
반응형
반응형

ReplicaSet 은 Replicatation Controller 의 새로운 버전이다.

 

다른것은 다 동일한데 아래와 같은 차이점이 존재 한다.

 

ReplcaSet : Set-based Selectors

Replicatation Controller : Equality-based Selectors

 

  Equality-based  Set-based
support  Service, Replication Controller Job, Deployment, ReplicaSet, Daemon Set
Operation  =, ==, != in, notin, exists
Example  enviroment=prd enviroment in (prd)
Command Line kubectl get pods -l enviroment=prd kubectl get pods -l 'enviroment in (prd)'
Manifest selector: 
  enviroment: prd
selector:
 matchExpressions: 
   - {key: enviroment, operation: In, values: [prd]}

 

추가적으로 sectors 에 matchLabels 가 존재할 경우 아래와 같은 차이점이 있다.

Manifest

selector:
  app: nginx 

selector: 
  matchLabels: 
     app: nginx
support  Services, Replication Controller ReplicaSets, Deployments, Jobs, DaemonSet|

 

참고자료

https://www.youtube.com/watch?v=Y5ADo_tjfIs&list=PLMPZQTftRCS8Pp4wiiUruly5ODScvAwcQ&index=19

728x90
반응형
반응형

VirtualBox 에서 Ubuntu Server 를 설치하고 폴더 공유하려다가 간신히 성공한 내용이다.  ㅡㅡ;;

 

보통 찾아보면 

 

Virtual Box 설정 -> 공유폴더 -> 머신 폴더 하위에 추가 -> 공유할 폴더 지정 

 

하라고 나온다.  그리고 나서 "장치" 메뉴에 "게스트 확장 이미지 삽입" 이라고 하면 자동으로 무엇인가가 설치 된다고 나오던데 그것도 안되더라...

 

그럼 우선 위에 언급한 거에서 "게스트 확장 이미지 삽입" 까지는 동일하다.

 

그 다음 다음과 같이 진행한다. 

 

# 게스트 확장 이미지를 바인드할 디렉토리 생성 & cdrom mount

mkdir tools

cd tools

sudo mount /dev/cdrom ./tools/

 

이렇게 하면 시디롬에 있던 정보들이 tools 디렉토리로 들어온다. 

 

그리고 나서 

sudo ./VBoxLinuxAdditions.run 을 실행시킨다.

 

그럼 사전 작업 완료

 

# 공유폴더 연결

mkdir share

sudo mount -t vboxsf [지정한폴더이름] ./share/

 

이렇게 하면 로컬 pc 의 폴더와 guest 의 폴더가 공유가 된다. 

 

 

728x90
반응형
반응형

현재 브랜치와 다른 브랜치 사이에 merge가 아닌 특정 파일만 합치고 싶을때의 방법이다. 

 

git -p [브랜치명] -- [파일경로]

 

브랜치명 : 합쳐야 하는 내용들이 있는 브랜치 명을 입력하면 된다. (현재 브랜치가 아님)

파일경로 : 파일 path 를 넣으면 된다.

 

파일 경로 입력할때 다음과 같이 찾아보면 편리하다.

 

git diff --name-status [브랜치명]

 

이렇게 하면 현재 브랜치와 [브랜치명]에 있는 브랜치의 다른점 목록이 나온다. 

이 경로로 입력을 하면 된다. 

 

 

728x90
반응형
반응형

Virtual Box 에서 VM 을 띄우다 보면 화면의 해상도가 작을 때가 있다. 그래서 사용하기 상당히 불편한데 이것은 확장 패키지 설치로 해결할수 있다.


보통은 아래와 같이 메뉴에서 게스트 확장 CD 이미지 삽입.. 이부분 누르면 된다고 하는데 나는 저 버튼을 눌러도 아무 반응이 없었다.




그래서 다른 방법을 찾아 보던중 패키지를 받아서 수동으로 설치해주는 방법을 찾게 되었다.


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


위 사이트에 들어가면 아래와 같은 내용을 찾을 수 있다.



저 링크를 클릭해서 파일을 다운 받는다.




그리고 환경설정으로 들어가서 확장 메뉴에서 우측 버튼을 클릭해서 조금전 다운로드 받은 파일을 선택해준다. 




여기에서 설치를 진행하면 자동으로 알아서 다 실치가 된다.


그리고 나서 가상머신을 재부팅 해주고 나면 화면의 크기 조절시 해상도가 맞게 설정이 된다. 

728x90
반응형
반응형

컨트롤러를 만들어서 Testcase 를 작성한 후에 성공할거라 믿고 돌려봤는데 IllegalArgumentException 이 발생했다.

컨트롤러 코드와 테스트 케이스 코드는 각각 다음과 같다.


UserController.java

1
2
3
4
5
6
@GetMapping(value = "/users/{email}")
public UserDto.Res getUser(@PathVariable @Valid final String email){
    Optional<Users> users = userService.findByEmailValue(email);
 
    return new UserDto.Res(users.get());
}
cs


UserControllerTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Before
public void setUp(){
    users = Users.builder()
            .email(Email.builder().value("test@test.com").build())
            .firstName("TEST")
            .lastName("KIM")
            .password("password")
            .build();
}
 
@Test
public void getUserTest() throws Exception {
 
    given(this.userController.getUser("test@test.com")).willReturn(new UserDto.Res(this.users));
 
    ResultActions resultActions = this.mockMvc.perform(
            get("/users/{email}""test@test.com"))
            .andDo(print());
 
    resultActions
            .andExpect(jsonPath("firstName").value("TEST"))
            .andExpect(jsonPath("lastName").value("KIM"))
            .andExpect(MockMvcResultMatchers.status().isOk());
}
cs


Exception

Caused by: java.lang.IllegalArgumentException: Name for argument type [java.lang.String] not available, and parameter name information not found in class file either.


대체 뭐지??? 맞게 parameter 도 넘겼는데 왜 못찾는거지....



Spring Document 를 보니 다음과 같은 내용을 찾을수 있었다.

The matching of method parameter names to URI Template variable names can only be done if your code is compiled with debugging enabled. If you do have not debugging enabled, you must specify the name of the URI Template variable name to bind to in the @PathVariable annotation.

<출처 : https://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch18s02.html >


컴파일 할때 debugging enabled 가 되어야 동작을 하는데 그렇지 않을 경우에는 반드시 @PathVariable 사용시 name 에 값을 줘야 한다고 되어있다.


그럼 컴파일 할때 debugging enabled 는 뭔가?? -_-;;

java 소스를 컴파일할때 사용되는 javac 명령어를 찾아보면 다음과 같은 옵션이 있다. 컴파일시에 -g 옵션을 사용할 경우 로컬 지역변수(local variables) 를 포함한 debugging information 을 생성하고 디폴트로는 라인 넘버와 소스파일 정보만 생성된다고 써있다.


-g
Generate all debugging information, including local variables. By default, only line number and source file information is generated.
-g:none
Do not generate any debugging information.
-g:{keyword list}
Generate only some kinds of debugging information, specified by a comma separated list of keywords. Valid keywords are:
source
Source file debugging information
lines
Line number debugging information
vars
Local variable debugging information

<출처 : https://docs.oracle.com/javase/7/docs/technotes/tools/windows/javac.html>



그럼 간단한 자바 클래스를 컴파일 해서 확인해보자.


1
2
3
4
5
6
public class Test {
    public static void main (String[] args) {
        String name = "test";
        System.out.println(name);
    }
}
cs

javac Test.java (옵션 없이 할경우)

1
2
3
4
5
6
7
8
9
10
11
12
13
# javap -l Test                                 
Compiled from "Test.java"                       
public class Test {                             
  public Test();                                
    LineNumberTable:                            
      line 4: 0                                 
                                                
  public static void main(java.lang.String[]);  
    LineNumberTable:                            
      line 6: 0                                 
      line 7: 3                                 
      line 8: 10                                
}                                               
cs


javac -g Test.java (-g 옵션을 붙여서 할경우)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# javap -l Test
Compiled from "Test.java"
public class Test {
  public Test();
    LineNumberTable:
      line 40
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       5     0  this   LTest;
 
  public static void main(java.lang.String[]);
    LineNumberTable:
      line 60
      line 73
      line 810
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0      11     0  args   [Ljava/lang/String;
          3       8     1  name   Ljava/lang/String;
}
cs


각각의 경우를 javap 명령어로 확인해 보았다. (javap 명령어는 컴파일된 class 파일을 역 어셈블 해주는 명령어 있다. -l 옵션을 붙이면 로컬변수 테이블까지 보여준다.)


첫번째에서는 기본적으로 라인만 보이는데 두번째에서는 로컬 변수까지 다 보여준다. 


결론적으로 맨 처음 Testcase 에서 발생했던 문제는 UserController.java 를 컴파일 했을때 -g 옵션이 안들어가서 컴파일 후에 @PathVariable 에 있는 변수를 못찾아서 발생한 문제였다. 이게 IntelliJ 에서 따로 compile 옵션설정을 해야 할지는 잘 모르겠는데 나는 @PathVariable 에 name 을 명시해주는 방법으로 해결을 했다.


참고자료

https://www.logicbig.com/tutorials/spring-framework/spring-web-mvc/spring-path-variable.html

https://objectpartners.com/2010/08/12/spring-pathvariable-head-slapper/

https://www.logicbig.com/tutorials/spring-framework/spring-web-mvc/parameter-name-discoverer.html

https://stackoverflow.com/questions/5746894/what-does-the-javac-debugging-information-option-gvars-do

728x90
반응형
반응형

- 숨겨진 폴더, 파일 보이기(Finder에서)


Shift + Command + .


- 화면 캡쳐


Command + control + 3 : 전체화면 캡쳐

Command + control + 4 : 영역 지정해서 캡쳐


728x90
반응형
반응형

gitignore 파일을 작성을 했는데 이상하게도 계속 해당 파일들이 Untracked Files 에 잡혔다.



그런데 분명히 내가 작성한 gitignore 파일에는 다음과 같이 존재하고 있었다.

.idea/

.DS_Store

그래서 구글링을 해보니 아래와 같이 해결책을 제시해줬다.


https://stackoverflow.com/questions/32384473/gitignore-not-ignoring-idea-path


첫번째 시도


git rm -rf .idea/


Git에서 파일을 제거하려면 git rm 명령으로 Tracked 상태의 파일을 삭제한 후에(정확하게는 Staging Area에서 삭제하는 것) 커밋해야 한다. 이 명령은 워킹 디렉토리에 있는 파일도 삭제하기 때문에 실제로 파일도 지워진다.

<출처 : https://git-scm.com/book/ko/v2/Git%EC%9D%98-%EA%B8%B0%EC%B4%88-%EC%88%98%EC%A0%95%ED%95%98%EA%B3%A0-%EC%A0%80%EC%9E%A5%EC%86%8C%EC%97%90-%EC%A0%80%EC%9E%A5%ED%95%98%EA%B8%B0>


그랬더니 다음과 같은 메세지가 나왔다.


fatal: pathspec '.idea/' did not match any files


상황을 보아 하니 rm 명령어가 Tracked 상태의 파일을 삭제하는 명령어 인데 위 파일들은 tracked 되지 않은 파일이기 때문에 없다고 나온것 같다.


두번째 시도


git clean -f -d .idea/


일단 이렇게 하니깐 Untracked 파일들이 다 지워지긴 했다.


그럼 이 명령어가 무엇을 의미하는지 한번 살펴보자.


워킹 디렉토리 청소하기

작업하고 있던 파일을 Stash 하지 않고 단순히 그 파일들을 치워버리고 싶을 때가 있다. git clean 명령이 그 일을 한다.

<출처 : https://git-scm.com/book/ko/v2/Git-%EB%8F%84%EA%B5%AC-Stashing%EA%B3%BC-Cleaning >


결과적으로 Untracked 파일들을 모두 지운다는 의미이다.... -_-;; 좀 무서운 명령어다.  설명에도 다음과 같이 써있다.


이 명령을 사용할 때는 신중해야 한다. 이 명령을 사용하면 워킹 디렉토리 안의 추적하고 있지 않은 모든 파일이 지워지기 때문이다. 명령을 실행하고 나서 후회해도 소용없다. 지워진 파일은 돌아오지 않는다. git stash –all 명령을 이용하면 지우는 건 똑같지만, 먼저 모든 파일을 Stash 하므로 좀 더 안전하다.

워킹 디렉토리의 불필요한 파일들을 전부 지우려면 git clean 을 사용한다. 추적 중이지 않은 모든 정보를 워킹 디렉토리에서 지우고 싶다면 git clean -f -d 명령을 사용하자. 이 명령은 하위 디렉토리까지 모두 지워버린다. -f 옵션은 강제(force)의 의미이며 "진짜로 그냥 해라"라는 뜻이다.


한마디로 한번 지우면 되돌릴수 없다라는 의미이다. 

문제를 해결 하긴 했지만 위 명령어를 사용할 때에는 좀 신중할 필요는 있어보인다.



728x90
반응형
반응형

최근에 시간 관련 Data 를 가지고 삽질을 해서 간단히 적어본다.


상황은 이렇다. 

테이블에 특정 Data 를 저장 하고 있었는데 colum 에 언제나 그렇듯 생성 날짜, 시간 형태의 컬럼이 존재하고 있었다. Timestamp type 이었고 Data 는 잘 insert 가 되는 상황이었다. 그런데 이상하게 나는 분명 UTC 기준으로 Data 가 insert 될거라 생각을 했는데 그게 아니었다. Local 기준으로 Data 가 들어가고 있었다. 그러다 보니 이 Data를 사용하는 곳에서 예상치 못한 오류가 발생했다. 


1
2
3
4
5
6
@Test
public void jodaTime(){
    DateTime dateTime = new DateTime(DateTimeZone.UTC);
    System.out.println("dateTime : " + dateTime);
    System.out.println("dateTimeToDate : " + dateTime.toDate());
}
cs


문제가 된 부분은 위에 코드에 toDate() 부분이었다. 위 코드를 실행하면 결과는 아래와 같이 나온다. 


1
2
dateTime : 2019-02-13T07:01:03.407Z
dateTimeToDate : Wed Feb 13 16:01:03 KST 2019
cs


뭔가 좀 이상하다. dateTime 은 UTC 기준으로 나왔지만 toDate 값은 로컬 기준으로 나온다. 그리고 그 값이 DB 로 저장이 되고 있었다. 


Why????


위에 있는 toDate() 함수는 아래와 같이 구현이 되어있다. 그런데 여기에서 저 Date 가 문제다.


1
2
3
public Date toDate() {
  return new Date(getMillis());
}
cs


1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* Allocates a <code>Date</code> object and initializes it to
* represent the specified number of milliseconds since the
* standard base time known as "the epoch", namely January 1,
* 1970, 00:00:00 GMT.
*
* @param   date   the milliseconds since January 1, 1970, 00:00:00 GMT.
* @see     java.lang.System#currentTimeMillis()
*/
public Date(long date) {
  fastTime = date;
}
 
cs


@see 를 보면 java.lang.System을 참조하고 있다. -_-;. 그런 결과 아무리 앞에서 offset을 설정해봐야 결과값은 로컬에 있는 jvm 의 timezone을 따라간다는 거다. 


만약 DB 에 컬럼 타입이 String 이었다면 이렇게 하면 해결이 되긴 한다.


1
2
3
4
5
DateTime dateTime = new DateTime(DateTimeZone.UTC);
System.out.println("dateTime : " + dateTime);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat();
simpleDateFormat.setTimeZone(TimeZone.getTimeZone(ZoneId.of("UTC")));
System.out.println("dateTimeToDateFormatter : " + simpleDateFormat.format(dateTime.toDate()));
cs


1
2
dateTime : 2019-02-13T08:07:53.819Z
dateTimeToDateFormatter : 19. 2. 13 오전 8:07
cs


값은 동일하게 나오긴 하지만 그렇다고 DB 컬럼을 바꾸기에는 뭔가 좀 부담스럽다.

그러면 어떻게 하는게 좋을까... 생각을 해보다가 이런 방법을 생각했다.


1. 현재 로컬의 OffsetDateTime 을 구한다. 

2. 그리고 로컬에 있는 Timezone 의 offset을 구한다.

3. offset 에 따른 시간 차이를 분 또는 초로 환산한다.

4. 환산한 값을 현재 로컬 Time 값에서 빼거나 더한다. 


절차가 좀 복잡 하긴 하지만 DB 에는 UTC 값을 저장할 수 있게 된다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public void getUTC(){
    OffsetDateTime now = OffsetDateTime.now();
    System.out.println("현재 시간 : " + now);
 
    // Offset
    ZoneOffset offset = now.getOffset();
    System.out.println("offset : " + offset);
 
    // Offset 을 second 로 변경
    int totalSeconds = offset.getTotalSeconds();
    System.out.println("totalSeconds : " + totalSeconds);
 
    OffsetDateTime offsetDateTime = null;
    if (totalSeconds > 0){
        offsetDateTime = now.minusSeconds(totalSeconds);
    }else{
        offsetDateTime = now.plusSeconds(totalSeconds);
    }
 
    System.out.println("offsetDateTime : " + offsetDateTime);
}
cs


1
2
3
4
현재 시간 : 2019-02-14T13:30:38.592+09:00
offset : +09:00
totalSeconds : 32400
offsetDateTime : 2019-02-14T04:30:38.592+09:00
cs


여기에서 plus 와 minus 할때 totalSecond 값이 음수이냐 양수이냐 에 따라서 반대로 해야 한다. 우리 나라 같은 경우 +9시간이기 때문에 UTC로 맞추려면 빼줘야 한다. 


시간 들어가는 DATA 값은 정말 복잡하고 생각해야 될 것이 많은 것 같다.



728x90
반응형

+ Recent posts