리눅스에서는 base64 명령으로 base64 인코딩, 디코딩을 쉽게 할 수 있다.

 

1.  문자열 인코딩, 디코딩

1

2

3

4

5

6

7

// base64 encoding (with new_line)

# echo 'hello world' | base64

aGVsbG8gd29ybGQK

 

// base64 decoding

# echo 'aGVsbG8gd29ybGQK' | base64 --decode

hello world

 

이 때 주의할 점은 개행(\n)이 함께 인코딩 된다는 점이다.

개행을 제외하여 인코딩을 하고자 할 경우에는 -n 옵션을 추가하여 인코딩을 한다.

1

2

3

4

5

6

7

// base64 encoding (without new_line)

# echo 'hello world' | base64

aGVsbG8gd29ybGQ=

 

// base64 decoding

# echo 'aGVsbG8gd29ybGQ=' | base64 --decode

hello world#

 

2. 파일 인코딩, 디코딩

파일을 이용하여 인코딩, 디코딩을 할 수 있다.

1

2

3

4

5

6

7

// base64 encoding

# echo 'hello world' | base64 > hello.txt

# cat hello.txt

aGVsbG8gd29ybGQK

// base64 decoding

# base64 -di hello.txt

hello world

'IT기술 > 리눅스' 카테고리의 다른 글

리눅스에서 base64 인코딩, 디코딩 하는 방법  (0) 2019.10.27

FQDN은 '절대 도메인 네임' 또는 '전체 도메인 네임' 이라고도 불리는

도메인 전체 이름을 표기하는 방식을 의미한다.

 

웹 사이트 주소를 예로 들어보자.

 

1. www.tistory.com  

2. onlywis.tistory.com

 

위의 두 주소 중 www  onlywis 부분이 '호스트'이고, tistory.com 부분이 '도메인'이다.

위에 쓴 것처럼 호스트와 도메인을 함께 명시하여 전체 경로를 모두 표기하는 것을 FQDN 이라 한다.

 

FQDN와 달리 전체 경로명이 아닌 하위 일부 경로만으로 식별 가능하게 하는 이름을 PQDN(Partially~)라 한다.

 

쿠버네티스의 경우 다른 Pod를 찾을 시 동일 네임스페이스 안에서 찾을 때에는 PQDN을 사용할 수 있지만,

네임스페이스 외부에서 찾을 때에는 FQDN을 사용해야 한다.

'IT기술 > 네트워크' 카테고리의 다른 글

FQDN(Fully Qualified Domain Name) 이란?  (0) 2019.09.29

예전에는 수 개월(혹은 수 년)에 한 번씩 서비스를 릴리즈 했었지만, 최근에는 서비스를 더 작게 만들고(마이크로서비스) 더 자주 배포(Deployment) 하는 방식으로 변화하고 있다. 이러한 트렌드에 맞춰 서비스 배포 전략도 다양하게 개발되고 발전되어 왔다.


본 포스트에서는 가장 대표적인 배포 전략 Rolling, Blue/Green, Canary 기법에 대해 알아보겠다.



1. Rolling

Rolling 배포는 서버를 한 대씩 구 버전에서 새 버전으로 교체해가는 전략이다. 서비스 중인 서버 한 대를 제외시키고 그 자리에 새 버전의 서버를 추가한다. 이렇게 구 버전에서 새 버전으로 트래픽을 점진적으로 전환한다. 이와 같은 방식은 서버 수의 제약이 있을 경우 유용하나 배포 중 인스턴스의 수가 감소 되므로 서버 처리 용량을 미리 고려해야 한다.




2. Blue/Green

Blue/Green 배포는 구 버전에서 새 버전으로 일제히 전환하는 전략이다. 구 버전의 서버와 새 버전의 서버들을 동시에 나란히 구성하고 배포 시점이 되면 트래픽을 일제히 전환시킨다. 하나의 버전만 프로덕션 되므로 버전 관리 문제를 방지할 수 있고, 또한 빠른 롤백이 가능하다. 또 다른 장점으로 운영 환경에 영향을 주지 않고 실제 서비스 환경으로 새 버전 테스트가 가능하다. 예를 들어 구 버전과 새 버전을 모두 구성하고 포트를 다르게 주거나 내부 트래픽일 경우 새 버전으로 접근하도록 설정하여 테스트를 진행해 볼 수 있다. 단, 시스템 자원이 두 배로 필요하고, 전체 플랫폼에 대한 테스트가 진행 되어야 한다.




3. Canary

'Canary'라는 용어의 어원을 알면 이해가 더 쉽다. Canary는 카나리아 라는 새를 일컫는 말인데, 이 새는 일산화탄소 및 유독가스에 매우 민감하다고 한다. 그래서 과거 광부들이 이 새를 옆에 두고 광산에서 일을 하다가 카나리아가 갑자기 죽게 되면 대피를 했다고 한다.

Canary 배포는 카나리아 새처럼 위험을 빠르게 감지할 수 있는 배포 기법이다. 구 버전의 서버와 새 버전의 서버들을 구성하고 일부 트래픽을 새 버전으로 분산하여 오류 여부를 판단한다. 이 기법으로 A/B 테스트도 가능한데, 오류율 및 성능 모니터링에 유용하다. 트래픽을 분산시킬 라우팅은 랜덤으로 할 수도 있고 사용자 프로필 등을 기반으로 분류할 수도 있다. 분산 후 결과에 따라 새 버전이 운영 환경을 대체할 수도 있고, 다시 구 버전으로 돌아가 수도 있다.





[참고]

https://www.slideshare.net/awskorea/ci-cd-pipleine-on-aws

https://dev.to/mostlyjason/intro-to-deployment-strategies-blue-green-canary-and-more-3a3

'IT기술 > DevOps' 카테고리의 다른 글

배포 전략: Rolling, Blue/Green, Canary  (1) 2019.03.12
CI/CD란 무엇인가?  (0) 2019.03.08
  1. 마법삼 2019.10.14 15:45

    잘 봤습니다~, 큰 도움 되었습니다.

1. CI/CD 개념

  - 애플리케이션 개발 단계를 자동화하여 보다 짧은 주기로 배포하는 전략 또는 방법

  - 코드통합, 테스트, 릴리즈, 배포(Deployment) 등의 애플리케이션 라이프사이클 전체 과정을 자동화하고 이 과정을 모니터링 가능토록 하는 것. (연속된 과정을 "CI/CD 파이프라인" 이라고도 한다.)

  - 개발자가 아닌 사람도 쉽게 빌드, 배포를 가능하도록 하는 것 -> 개발자는 개발에만 집중


2. 대상 시점

CI와 CD는 세부적으로 아래와 같이 나눠지며, 개발/배포 단계에 적용되는 전략이 달라진다.



3. CI - Continuous Integration

  - 개발자를 위한 자동화 프로세스

  - 개발자간의 코드 충돌을 방지하기 위한 목적

  - 정기적인 빌드 및 테스트(유닛테스트 및 통합테스트)를 거쳐 공유 레포지터리에 병합되는 과정


4. CD(1) - Continuous Delivery

  - 애플리케이션에 적용한 변경사항이 버그 테스트를 거쳐 레포지터리에 자동으로 업로드 되는 것

  - 운영팀은 언제든 실시간으로 이 레포지터리에서 실시간으로 프로덕션 환경으로 배포 가능


5. CD(2) - Continuous Deployment

  - 애플리케이션을 프로덕션 환경으로 배포하는 작업을 자동화 하는 것

  - 서버가 여러 대 일 경우 더욱 중요

  - Continuous Delivery로 통칭하여 언급하기도 함


6. CI/CD 지원 툴

  - Hudson

  - Jenkins

  - Bamboo(상용)

  - 그 외 다양한 툴 존재


7. CI/CD의 핵심 목적

한 번에 많이 수정하지 말고, 조금 수정하여 여러 번 배포하라!




[참고문서]

https://www.redhat.com/ko/topics/devops/what-is-ci-cd


'IT기술 > DevOps' 카테고리의 다른 글

배포 전략: Rolling, Blue/Green, Canary  (1) 2019.03.12
CI/CD란 무엇인가?  (0) 2019.03.08

boxplot 사분위값을 이용하여 데이터의 분표 모양, 대칭성, 극단 값을 쉽게 파악할 있는 그림이다.

크게 중앙 50% 데이터의 분포 형태를 파악하는 부분과 나머지 50%(outlier) 분포 형태를 파악하는 부분 가지로 나누어 있다.


[5, 10,  15, 15, 16, 16, 20, 20, 20, 21, 25, 45, 50]


위의 데이터에서 사분위값은 아래와 같다


1사분위(Q1) = 15

2사분위(Q2) = 20

3사분위(Q3) = 25

(사분위값을 구하는 방법은 여러가지가 있다방법에 따라 값이 달라질  있다.)


Q1 Q3 끝으로 하는 상자를 그리고 Q2 실선으로 그어 중앙 50% 데이터가 어떻게 분포되어 있는지 나타낸.


나머지 50% 분포는 IQR 이용하여 그린다.

IQR(InterQuartile Range) 'Q1 Q3 사이 길이'이다.


Q1 Q3 주변으로 1.5 * IQR 범위에 있는 데이터를 울타리 안에 표시하고,

바깥에 있는 데이터는 * 또는 O 으로 표시한다.

(이때 울타리 안의 데이터를 'suspect outliers' 하고울타리 밖의 데이터를 'highly suspect outliers' 한다.)


IQR = 25 - 15 = 10

1.5*IQR = 15

Q1 - 1.5*IQR = 15 - 15 = 0

Q3 + 1.5*IQR = 25 + 15 = 40


위에서 구한 값을 그림으로 그리면 다음과 같다.




'통계' 카테고리의 다른 글

boxplot(상자그림) 설명  (0) 2019.02.10

1. 금새 vs 금세


'금시에'의 줄인말인 '금세'가 올바른 표현이다.




2. 그새 vs 그세


'그 사이'의 준말인 '그새'가 올바른 표현이다.




3. 어느새 vs 어느세


'어느 사이'의 준말인 '어느새'가 올바른 표현이다.




'언어 > 우리말' 카테고리의 다른 글

맞춤법(금새vs금세/그새vs그세/어느새vs어느세)  (0) 2018.09.30

프로그래밍에서 시간을 표현하거나 계산 할 때 년/월/일/시/분/초를 나누어 표현 또는 계산하는 방법도 있으나,

Timestamp를 사용하는 경우도 자주 있다.


Timestamp란 특정 시간을 기준으로 지금까지 경과된 시간을 나타내는 숫자이다.


년/월/일/시/분/초 형식으로 구분하여 사용하면 인간이 읽기에는 편하나 더하고 빼고 등의 시간 계산을 하기에는 복잡하고 비효율적이다.

그래서 이러한 경우에는 Timestamp를 자주 사용한다.


Timestamp를 통신에 사용할 경우 주의해야 할 점이 있는데 OS 또는 언어마다 Timestamp의 기준시와 단위가 달라진다는 점이다.


OS 별 Timestamp는 다음과 같다.


<Unix>

 time_t

 UTC 1970년 1월 1일 0시 0분 0초를 기준으로 하는 초 단위의 시간을 저장하는 형식

https://ko.wikipedia.org/wiki/Time.h

2038년 문제를 주의해야 한다. 32bit 자료형을 사용할 경우 2038년 1월 19일까지 밖에 표현하지 못한다.


<Windows>

FILETIME

Contains a 64-bit value representing the number of 100-nanosecond intervals

since January 1, 1601 (UTC).

https://msdn.microsoft.com/ko-kr/library/windows/desktop/ms724284(v=vs.85).aspx



Windows에서 사용하는 Timestamp는 1601년 1월 1일 0시부터 지금까지의 시간을 100 나노초 단위로 표시한다.

반면 Unix에서는 1970년 1월 1일 0시부터 지금까지 경과된 시간을 초 단위로 표시한다.

Python은 Unix와 동일한 Timestamp를 사용한다.


그렇기 때문에 통신에서 Timestamp를 사용할 경우에는 OS에 따라 변환 과정을 거쳐야 한다.


변환 방법은 1)단위를 통일하고 2)기준시간을 변경하면 된다.



예를 들어 현재 시점으로 만들어진 Timestamp를 변환한다고 가정해 보자.

작업 환경이 Windows 라면 의 크기가 Timestamp가 될 것이고 Unix 라면 가 될 것이다.


로 변환하기 위해서는 우선 단위를 '100나노초'에서 '초'로 변경하고 를 빼면 된다.


의 크기는 116444736000000000 나노초 또는 11644473600 초 이다.

그리고 나노초를 초로 변경하기 위해서는 10000000을 곱하면 된다.


WinAPI를 기준으로 아래와 같이 구현할 수 있다.


1
2
3
4
5
6
7
8
9
LARGE_INTEGER Win2UnixStamp (LARGE_INTEGER largeWinStamp)
{
    LARGE_INTEGER largeUnixStamp;
    LARGE_INTEGER largeUnixInitValue;
    largeUnixInitValue.QuadPart = 11644473600// UNIX time_t 1970/01/01 00:00 (UTF)
    largeUnixStamp.QuadPart = (largeWinStamp.QuadPart / 10000000- largeUnixInitValue.QuadPart;
    return largeUnixStamp;
 
}
cs


1
2
3
4
5
6
7
8
LARGE_INTEGER Unix2WinStamp (LARGE_INTEGER largeUnixStamp)
{
    LARGE_INTEGER largeWinStamp;
    LARGE_INTEGER largeUnixInitValue;
    largeUnixInitValue.QuadPart = 116444736000000000;
    largeWinStamp.QuadPart = (largeUnixStamp.QuadPart * 10000000+ largeUnixInitValue.QuadPart;
    return largeWinStamp;
}
cs


이전 포스트에서 rand() 함수의 취약점을 설명하였다.


rand() 함수를 보완한 랜덤 함수가 CryptGenRandom() 함수이다.


CryptGenRandom 함수는 crpytographic service provider(CSP)를 이용한 랜덤 함수로 암호학적으로 랜덤하게 난수값을 생성한다. 다만, rand() 함수에 비해 매우 느리다는 단점이 있다.


사용 방법은 아래와 같다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#include "stdafx.h"
#include <Windows.h>
#include <STDIO.H>
#include <Wincrypt.h>
 
#define MAX_RANDOM_NUM 100
 
int main(int argc, char* argv[])
{
    //--------------------------------------------------------------------
    // 변수를 선언하고 초기화 합니다.
    HCRYPTPROV   hCryptProv;
    BYTE         pbData;
 
    //-------------------------------------------------------------------
    // 암호 제공자의 컨텍스트 핸들을 얻습니다.
    if (CryptAcquireContext(&hCryptProv, NULLNULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))
    {
        printf("New CryptAcquireContext succeeded. \n");
    }
    else
    {
        printf("Error 0x%x during CryptAcquireContext!\n", GetLastError());
        goto ERR;
    }
 
    //--------------------------------------------------------------------
    // BYTE 범위내에서 난수를 생성합니다.
    if(CryptGenRandom(hCryptProv, 1&pbData)) 
    {
        printf("Random number is: %d.\n", ((int)pbData) * MAX_RANDOM_NUM / 255);
    }
    else
    {
        printf("Error 0x%x during CryptGenRandom.\n", GetLastError());
        goto ERR;
    }
 
ERR:
    //-------------------------------------------------------------------
    // 컨텍스트 핸들을 해제합니다.
    if(hCryptProv)
    {
        if (!CryptReleaseContext(hCryptProv, 0))
        {
            printf("Failed CryptReleaseContext\n");
        }
    }
 
    return 0;
}
cs



CryptGetRandom() 함수는 현재 deprecated 되었다.

Cryptography Next Generation APIs를 사용해라.


<본 글은 win32 api를 바탕으로 작성되었습니다.>


개발을 하다 보면 랜덤 값을 생성해야 하는 경우가 있다. 이때 자주 사용되는 함수가 rand() 함수이다.



* rand() 함수 설명


C에서 rand() 함수는 랜덤 값을 생성하는 함수이다.

rand() 함수 사용법은 아래와 같다.


1
2
3
4
5
6
int i;
unsigned int nSeed = 1000;
 
srand(nSeed);
for( i = 0; i < 10; i++ )
    printf("%d ", rand() );
cs


seed 값을 설정하고 rand() 함수를 호출하면 0~0x7fff 사이의 값이 랜덤으로 리턴된다.

srand() 함수에 seed 값을 주면 전달 된 seed 값을 기준으로 정해진 알고리즘에 따라 0~0x7fff 사이의 랜덤 값 리스트를 생성하게 된다.

그 후 rand() 함수를 호출하면 랜덤 값 리스트에서 값을 순서대로 하나씩 꺼내 리턴한다.



* rand() 함수의 한계


결론부터 말하자면 rand() 함수는 보안에 취약하므로 사용하지 마라.

위에서 설명했듯이 rand() 함수는 srand() 함수를 통해 생성된 리스트에서 값을 하나씩 꺼내게 되고,

srand() 함수는 전달 된 seed 값을 기준으로 정해진 알고리즘에 따라 리스트를 생성한다.

즉, seed 값을 알게 되면 rand() 함수로부터 리턴 될 값을 예측할 수 있게 된다.


아래 코드를 보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void rand_test_1()
{
    int i;
    unsigned int nSeed = 1000;
 
    srand(nSeed);
    for( i = 0; i < 10; i++ )
        printf("%d ", rand() );
 
    printf("\n");
}
 
int main(int argc, char* argv[])
{
    rand_test_1();
    Sleep(1000);
    rand_test_1();
    Sleep(1000);
    rand_test_1();
 
    return 0;
}
cs


결과는 다음과 같다.

1
2
3
4
3304 8221 26849 14038 1509 6367 7856 21362 6968 10160
3304 8221 26849 14038 1509 6367 7856 21362 6968 10160
3304 8221 26849 14038 1509 6367 7856 21362 6968 10160
Press any key to continue
cs


seed 값을 알게 되면 그 다음 생성되는 랜덤 값은 항상 같게 되고 이를 유추할 수 있게 된다.

그래서 seed 값을 추측할 수 없게 하기 위해 seed를 현재 시간으로 하기도 한다.


아래 코드는 time() 함수를 사용하여 seed 값에 현재시간 정보를 넣은 코드이다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void rand_test_2()
{
    int i;
    unsigned int nSeed = (unsigned)time( NULL );
 
    srand(nSeed);
    for( i = 0; i < 10; i++ )
        printf("%d ", rand() );
 
    printf("\n");
}
 
int main(int argc, char* argv[])
{
    rand_test_2();
    Sleep(1000);
    rand_test_2();
    Sleep(1000);
    rand_test_2();
 
    return 0;
}
cs


결과는 아래와 같다.

1
2
3
4
22734 32447 12644 11773 13510 15387 24256 27097 22692 24687
25993 11452 15295 8016 18303 2103 17522 22028 18955 16531
29304 31360 8861 28825 24290 18879 27819 2892 17260 8311
Press any key to continue
cs


이렇게 하면 seed 값을 유추하기 어려우나 이는 어려운 것일 뿐 불가능한 것은 아니다.


암호학적으로 랜덤한 값을 만들기 위해 Unix 계열에서는 '/dev/random' 또는 '/dev/urandom'를,

Windows 계열에서는 'CryptGenRandom()' 함수를 사용하는 것이 좋다. (CryptGetRandom() 함수는 deprecated 되었다. Cryptography Next Generation APIs를 사용해라)

  1. T2 2018.09.13 07:11

    보안 취약점 말고도 또 하나 문제가 시간으로 시드 줬을때 표현 범위 때문이였던가 뭐였던가 여튼 테스트 컴퓨터 시간을 엄청 미래로 바꾸고(몇백년 단위) 테스트하면 무조건 똑같은 값만 주게 되죠 그래서 옛날 c로 만든 게임들에서 버그성으로 이용 하기도 했었죠


1
2
3
4
5
6
7
8
9
>>> def f (x, y=[]) :
    y.append(x)
    print(y)
>>> def test () :
    f('a')
    f('a')
    f('a')
>>> test()

cs


9번째 라인의 출력 결과는 어떻게 될까?

위 코드의 결과는 아래와 같다.


1
2
3
4
>>> test()
['a']
['a''a']
['a''a''a']
cs


나는 당연히 ['a']가 세 번 출력될 것이라 예상했는데 이전 값들이 계속 남아 출력되어 적잖이 당황했다.

정황으로 보아 f 함수의 y 변수가 지워지지 않고 계속 남아있는 것으로 보이는데 이해가 되지 않았다.

y 변수는 분명 지역변수로 매번 생성 될텐데 어째서 지워지지 않았을까.


이러한 내용과 관련하여 검색을 해보고 아래와 같은 사실을 알게 되었다.

Default Parameter Values in Python 참고


python에서 함수 인자의 기본값으로 "mutable" 성격의 오브젝트가 선언되고 그 기본값을 통해 변수가 생성될 경우 해당 변수는 static 변수의 성격을 갖게 된다.


일부 사이트에서는 인자의 기본값이 mutable 이면 global 변수가 된다고 하는데,

변수의 life time은 global 이지만 scope이 함수 내부여서 global 변수 보다는 static 변수로 보는 것이 맞을 것 같다.


이러한 이유 때문에 동일한 함수(위 코드에서 f 함수)를 계속 호출하면 매번 y 리스트가 새로 생성되는 것이 아니라, 이전에 호출 되었던 y 변수를 다시 불러와 다시 사용하게 되는 것이다.


리스트, 딕셔너리 뿐만 아니라 클래스와 같은 오브젝트들도 함수 인자의 기본 값으로 사용하게 될 경우 위의 내용과 동일하게 동작한다.


이러한 문제를 해결하기 위한 방법은 여러가지가 있을 것인데 아래 코드와 같이 바꿔서 사용할 수도 있다.


1
2
3
4
5
6
>>> def f (x, y=None) :
    if y is None:
        y=[]
    y.append(x)
    print(y)
 

cs


삽질을 피하기 위해 인자의 기본 값 설정 시에는 가능하면 "mutable" 한 오브젝트는 사용하지 말자.

'프로그래밍 > python' 카테고리의 다른 글

[python] default value 사용 시 주의사항  (0) 2018.01.18

+ Recent posts