[TIL]20210723

박창현·2021년 7월 23일
0

TODAY I LEARNED

목록 보기
22/53

쿠버네티스

강의들으면서 필요한거 정리
pod은 컨테이너를 포장해놓는 포장지 느낌. 하나이상의 컨테이너의 그룹.

🐳 쿠버네티스 v1.21.2 을 Docker 20.10.6 런타임으로 설치하는 중
이라는 말이 docker를 실행하기 위한 런타임 패키지 역할을 쿠버네티스가 담당한다. 이정도로 이해하면 되는건가?

deployment는 pod들을 관리하기 위한 최상위의 자원. 이가 만들어지면 ReplicaSet이 만들어짐. 이 Set는 pod 몇 개로 실행시킬 것인가를 결정. replica(복제품)을 여러개 동작시켜 트래픽을 분산시키기 위해.

deployment는 컨테이너의 명세서 느낌.

pod이 죽으면 다시 만든다고 했는데 pod이 죽는 경우의 수가 뭐가 있을까?--> 매우 많다. 그냥 프로그램이 꺼져서라고만 생각하자.
쿠버네티스가 선언적으로 작동하는 것이 즉, 만들거나 없애는 과정은 K8s의 자원들이 알아서하고 우리가 요구한 사항만 맞춰줘! 이뜻인건가?

pod은 ip주소가 매번 다름. 그렇기에 service를 통해 접근한다. 서비스는 고정이기에 pod이 재생성되도 k8s가 알아서 매칭시켜줌.

나의 경우 도커에 속해있는 k8s가 docker ps -a를 해도 보이지 않았는데 왜그럴까..

clusterip를 이용하기때문에 외부에 접속을 못해 인그레스를 사용하면 애초에 clusterip를 사용하지않고 nodeport를 사용하면 되지 않나?? --> 각각의 용도가 다름. nodeport는 1. 포트당 한 서비스만 할당할 수 있다. 2. 30000-32767 사이의 포트만 사용할 수 있다. 3. Node나 VM의 IP 주소가 바뀌면, 이를 반영해야 한다. 라는 특징이 있고, ingress는 “스마트”하기 때문에 다양한 기능을 활용할 수 있다. 아마도 서비스를 외부에 노출하는 가장 강력한 방법이겠지만 가장 복잡한 방법일 수 있다.
출처: https://blog.leocat.kr/notes/2019/08/22/translation-kubernetes-nodeport-vs-loadbalancer-vs-ingress

파알인 정리

1~106p

타입 힌트

한학기동안 파이썬을 사용하면서 함수의 타입을 지정해준 적이 없는거 같다. 하지만, 만약 def fn(a):에서 a 이라는 파라미터에 0을 넘길때 숫자로 넘길지 문자로 넘길지를 알 수가 없어 나중에 규모가 큰 프로젝트를 수행할 경우 가독성을 떨어뜨리고 버그 유발의 주범이 된다고 한다.

a: str = '1'
b: int = 1

def fn(a:int) ->bool:
    ...

하지만 여전히 동적으로 할당 될 수 있어 문자열에 정수를 할당하는 등의 방식은 조심하면서 지양해야한다고 함.

>>> a: str = 1
>>> type(a)
<class 'int'>

리스트 컴프리헨션

이는 기존의 리스트를 기반으로 새로운 리스트를 만들어내는 구문.

함수형 기능인 map을 사용하면
>>> list(map(lambda xL x+10,[1, 2, 3]))
[11,12,13]

리스트 컴프리헨션을 사용하면
>>> [n * 2 for n in range(1, 10 + 1) if n % 2 ==1]
[2, 6, 10, 14, 18]
일반적으로는
>>> a = []
>>> for n in range(1, 10 + 1):
...     if n% 2 ==1:
...         a.append(n * 2)


리스트(딕셔너리) 컴프리헨션을 사용하면
>>>a = {key: value for key, value in original.items()}
일반적으로는
>>> a = {}
>>> for key, value in original.items():
...     a[key] = value

일반적으로 컴르리헨션이 가독성이 좋지만 무리하게 복잡하게 작성하면 오히려 가독성이 저하된다는 것을 주의.

제너레이터

루프의 반복동작을 제어하는 루틴 형태.
제너레이터 없이 1억 개의 숫자를 만들어내려면 메모리 어딘가에 만들어낸 숫자 1억개를 보관해야하지만 제너레이터는 루틴만 보관하고 있어 메모리 사용량이 현저히 적다.

yield

함수에서 값을 돌려받을 때 return 을 주로 사용하고, 이는 함수를 종료시키지만 yield를 사용하면 중간값을 리턴한 다음 함수는 종료하지 않고 계속해서 실행된다!!!
그리고 이 값은 next를 통해 받아낼 수 있다.

def number():
    n = 0
    while True:
        n += 1
        yield n

n = number()
for _ in range(1, 100):
    print(next(number()))
    print(next(n))

위의 print는 계속 1을 출력하고 밑의 print는 1~99까지 출력한다.
이 두 print는 책에 나와있지 않지만 내가 헷갈려서 둘다 적는다. next(n)은 똑같은 number()라는 함수를 가진 상태에서 next를 하는 것이고 next(number())은 새로운 number()을 계속 불러오기 때문에 1이 출력된다.
다시 볼때 이해가 안간다면 이렇게 이해하자.(맞는지는 모르겠지만 이해는 얼추 될거같다.) C에서 for(int i=0; i < strlen(a); i++){} 하면 for문이 돌때마다 strlen을 매번 계산해줘야하고 len = strlen(a); for(int i=0; i< len; i++){} 하면 한번만 strlen을 해서 len이라는 변수에 저장해서 매번 새롭게 계산할 필요가 없어지는 것과 같다.

이러한 제너레이터 방식을 사용하는 대표적인 함수가 range()이다. 이 친구도 값을 가지고 있는 것이 아니라 제너레이터를 통해 값을 만든다.

import sys

a = [n for n in range(10000)]
b = range(10000)
print(a,len(a), sep = ('\n'))
print()
print(b, list(b), len(b), sep='\n',)
print()
print(sys.getsizeof(a))
print(sys.getsizeof(b))

출력값
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ....
10000

range(0, 10000)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ....
10000

85176
48

출력값을 보면 알 수 있듯 리스트를 선언한 a나 range인 b나 길이가 같다는 것을 알 수 있다. 출력시에도 list만 붙이면 a와 b는 같은 결과를 보여준다.
하지만 메모리 점유율은 다르다.
각각 85176, 48(range는 생성 조건만 보관함으로 점유율은 항상 고정)임을 알 수 있다. 메모리 점유율이 클수록 생성시간 또한 길어지는 것도 참고하자.

enumerate

'열거하다'는 뜻을 가진 함수. 여러가지 자료형을 인덱스를 포함한 enumerate 객체로 리턴함.

a=[1,2,3,2,45]
printf(list(enumerate(a))

출력
[(0, 1), (1, 2), (2, 3), (3, 2), (4, 45)]

이처럼 인덱스를 포함한다.

a=['a1', 'b2', 'c3']
for i in range(len(a))
    printf(i,a[i])

i=0
for v in a:
    print(i, v)
    i += 1

for i, v in enumerate(a):
    print(i,v)

위의 세가지 코드는 출력 값은 같으나 첫번째에선 불필요하게 a[i]값을 매번 조회해야하고(a의 i번째 값을 조회하는 것과 a리스트 내용을 순차적으로 불러오는 것하고 차이가 있나? 있을거같긴한데....), 두번째에서는 i를 지정해야한다는 단점이 있다. 마지막 방법이 가장 깔끔하다 볼 수 있음.

나눗셈 연산자

c에선 int값에서 5/3를 하면 몫만 나오지만
파이썬에선 정수에 5/3를 하면 float으로 변하면서 1.66xx를 출력한다.
//는 몫, %는 나머지를 구할 수 있다.

divmod

목과 나머지를 한 번에 구할 때 divmod(5, 3)을 하면 (1, 2)가 나온다!!!!

print

a = [1, 2, 3, 2, 45, 5]
b = 1
print("{} {}".format(b+1, a))
print(b+1, a)
print(f"{b+1} {a}")

밑의 3가지 모두 출력이 동일, 책의 저자는 가장밑의 경우(f-string)을 선호함.

pass

임시로 def: 밑의 내용을 안적었을때 실행하면 오류가 발생함으로 pass를 적어줌. 전체골격을 잡은후 내부내용을 차근차근 적을때 유용.

locals

로컬 심볼 테이블 딕셔너리를 가져온다는데 쉽게 말해 클래스 메소드 내부의 모든 로컬 변수를 가져온다.
print(locals())을 통해 출력할 수 있고,

import pprint
pprint.pprintf(locals)

을 통해 보기좋게 각 변수들을 줄바꿈해주면서 출력할 수 있다.

신기한 변수 지정방식(카멜 케이스, 파스칼 케이스, 스네이크 케이스)

카멜 케이스 camelCase || 단어의 첫문자는 모두 대문자로 시작. 단, 첫 단어의 시작문자는 소문자. 자바에서 주로 사용.
파스칼 케이스 PascalCase || 첫 단어의 시작 문자도 대문자.
스네이크 케이스 snakecase || 각 단어를 언더스코어()로 구분. 시작문자를 대문자로 해도 되고 소문자로 해도 됨. 파이썬에서 주로 사용.

구글 파이썬 가이드

가변 객체와 불변 객체에 대해서는 아직 잘 모르겠고,
True, False를 판별할 때 암시적인 방법을 이용하는 것이 간결하며 가독성이 좋다고한다.

Yes: if not users:
	 	print('no users')
 	 if foo == 0:
	 	print('no users')

No: if len(users) ==0:
		print('no users')
    if foo is not None and not foo:
	 	print('no users')

빅오와 자료형

Big-O: 입력값이 무한대로 향할때 함수의 상한을 설명하는 수학적 표기 방법. 이를 통해 시간 복잡도를 표현할 때는 최고차항만을 표기하며, 심지어 최고차항의 계수도 무시한다. (cs50에서 공부했지만 한번 더)
빅오 표기법의 대표적 종류 5가지
O(1) : 항상 실행 시간 동일.
O(log n) : 웬만한 n의 크기에도 시간차이가 크지 않다.
O(n) : 입력값만큼 실행 시간에 영향을 받음. 선형 시간 알고리즘이라고도 함.
O(n * log n) : 대부분의 효율 좋은 알고리즘이 이에 해당. 비교 기반 정렬 알고리즘은 이보다 빠를 수 없다.
O(n^2) : 비효율적인 알고리즘

알고리즘은 트레이드오프 관계임.
실행 시간이 빠르면 공간을 많이 차지할 수 밖에 없다.

분할 상환 분석 및 병렬화

분할 상환 분석은 내용을 아직 잘 이해 못하겠고,
병렬화는 코어의 수는 적지만 각각의 코어가 빠른 cpu대신 코어의 수가 많은 지만 각각의 코어가 느린 gpu를 사용해 병렬 연산을 빠르게 한다.

profile
개강했기에 가끔씩 업로드.

0개의 댓글