반응형

 

 

작성일: 2024년 4월 11일

 

 

Go 언어를 사용해서 CLI를 개발할 일이 생겼는데, 기존 C언어로 개발하던 개발 습성 때문인지 CLI를 개발할 생각하니까 귀찮고 짜증부터 났다.

Java처럼 CLI를 쉽게 개발할 수 있는 Go Package가 있지 않을까 싶어서 구글링을 해보니, 역시나 GoLang은 개발 도구나 Library package가 훌륭하다는 것을 또 한번 느끼게 되었다.

 

일단 딱 눈에 들어온 것은 Cobra library였다.

https://pkg.go.dev/github.com/spf13/cobra#section-readme

 

cobra package - github.com/spf13/cobra - pkg.go.dev

SetOutput sets the destination for usage and error messages. If output is nil, os.Stderr is used. Deprecated: Use SetOut and/or SetErr instead

pkg.go.dev

 

Cobra is a library providing a simple interface to create powerful modern CLI interfaces similar to git & go tools.
Cobra is also an application that will generate your application scaffolding to rapidly develop a Cobra-based application.

 

위 Cobra Web Docs 문서에서 소개하는 것처럼 Cobra는 library이면서, application scaffoling을 만들어주는 개발 도구이다.

그래서 단순하게 library reference만 읽고 사용법을 익히는 것이 아니라 Cobra 도구를 이용해서 scaffolding을 만들고, 그 scaffolding 안에서 나의 logic을 추가해야 한다.

Cobra의 개발 절차만 잘 따라하면, 시간을 팍팍 줄여가면서 CLI를 붕어빵 찍어내듯이 만들 수 있을 것 같은 느낌적인 느낌이 들었다.

그럼 그 개발 절차를 자세히 들여다 보면 이렇다.

 

 

https://www.youtube.com/watch?v=so3VZwdWcBg&t=4s 

 

 

 

 

 

 

Reference

https://yjwang.tistory.com/137

 

[Go-lang] Cobra를 사용해서 cli 프로그램 개발

cobra 사용해서 cli tool을 개발해보고자 한다. 아무래도 Infra 작업을 하다보면 cli tool이 있으면 편하겠다는 생각을 하곤하는데 생각한 김에 만들어보고자합니다. cobra 프로젝트는 kubectl에서도 사용

yjwang.tistory.com

 

 

https://www.sktenterprise.com/bizInsight/blogDetail/dev/2755

 

[Golang] Cobra를 이용한 CLI 유틸리티 만들기 | 개발자 Story | SKT Enterprise

현대사회에서 대부분의 유저들은 휴대폰이나 컴퓨터 화면을 통해 쉽고 편한 GUI(Graphic User Interface)를 선호합니다. 그러나 GUI로는 채우기 힘든 여전히 CLI(Command Line Interface)를 선호하는 분야도 많

www.sktenterprise.com

 

https://nangman14.tistory.com/97

 

Go로 커맨드를 실행할 수 있는 CLI를 구현해보자 (With Cobra)

CLI(Command Line Interface)란 터미널을 통해 사용자와 컴퓨터가 상호작용하는 인터페이스를 말합니다. CLI는 그래픽을 통해 직관적으로 사용할 수 있는 GUI(Graphic User Interface)와 달리 명령줄로만 입력을

nangman14.tistory.com

 

 

 

 

기타: 다른 방식의 CLI 개발 예제

 

https://dev.to/tidalmigrations/interactive-cli-prompts-in-go-3bj9

 

Interactive CLI prompts in Go

Tidal Migrations 💓 CLI applications Do you like CLI applications? We love them! At Tidal...

dev.to

 

 

https://github.com/manifoldco/promptui

 

GitHub - manifoldco/promptui: Interactive prompt for command-line applications

Interactive prompt for command-line applications. Contribute to manifoldco/promptui development by creating an account on GitHub.

github.com

 

반응형

 

Multiple Control Plane Diagram / In Place Upgrade from v1 to v2

 

Multiple Control Plane Diagram

In Place Upgrade A demonstration of how in place upgrades work, showing an upgrade from "v1" to "v2"

docs.google.com

 

Istio traffic management

 

Istio流量管理实现机制深度解析

Istio作为一个service mesh开源项目,其中最重要的功能就是对网格中微服务之间的流量进行管理,包括服务发现,请求路由和服务间的可靠通信。Istio体系中流量管理配置下发以及流量规则如何在数据面

zhaohuabing.com

 

Sidecar Injection and iptables,  traffic hijacking process in Istio

 

 

Sidecar injection and transparent traffic hijacking process in Istio explained in detail

Based on Istio version 1.11, this blog describes the sidecar pattern and its advantages. How sidecar be injected into the data plane, how traffic hijacking and forwarding is done, and how traffic is routed to upstream.

jimmysong.io

 

 

 

Envoy xDS Protocol

 

Envoy 中的 xDS REST 和 gRPC 协议详解

本文翻译自 Envoy 代码库中的文档,本文通过示例详解了 Envoy 的 xDS REST 和 gPRC 协议。

www.servicemesher.com

 

 

Simple Control Plane 구현 Example 

 

196. [Istio, Envoy] Envoy 기초 사용 방법 및 xDS 개념, 사용 방법, ADS와 Istio Pilot의 관계

이번 포스트에서는 Envoy의 기초적인 사용 방법 (xDS 및 설정 파일) 에 대해서 먼저 다룬 뒤, 이것이 I...

blog.naver.com

https://github.com/alicek106/envoy-eds-flask-demo

 

GitHub - alicek106/envoy-eds-flask-demo: Demo: How to use EDS for Envoy in Flask

Demo: How to use EDS for Envoy in Flask. Contribute to alicek106/envoy-eds-flask-demo development by creating an account on GitHub.

github.com

 

반응형

 

가끔 kubernetes에서 istio를 사용하다보면, Pod 내부의 iptables 구성 상태가 어떠한지 궁금할 때가 있다.

매번 여기저기 명령 찾아서 짜집기하고 있었는데, 이렇게 하니까 찾는 시간도 오래 걸리고, 나의 기억도 오래가지 않아서 여기에 메모를 하고 필요할 때마다 아래 명령을 copy & paste 해야겠다.

 

(이 명령은 Istio README.md에도 있으니까, 좀더 깊게 볼려면 Istio README.md에서 찾아보길~)

 

##
## pod의 container id 확인하기
##

$ ns=ns-a

$ podnm=ratings-v1-587d5cfb9-mxhxc

$ container_id=$(kubectl get pod -n ${ns} ${podnm} -o jsonpath="{.status.containerStatuses[?(@.name=='istio-proxy')].containerID}" | sed -n 's/docker:\/\/\(.*\)/\1/p')

$ echo $container_id
6dbeeb047da9149f0735943cd95885a156dbdc766b48145c40e7346ea7f6bcfb


##
## 어떤 worker node에서 ratings-v1 pod가 구동되어 있는지 확인하기
##

$ kubectl get -n ns-a pod -l app=ratings -o wide
NAME                         READY   STATUS    RESTARTS   AGE     IP               NODE      NOMINATED NODE   READINESS GATES
ratings-v1-587d5cfb9-mxhxc   2/2     Running   0          2d17h   10.244.91.198    node-73   <none>           <none>
ratings-v1-587d5cfb9-s6g6r   2/2     Running   0          2d17h   10.244.142.131   node-75   <none>           <none>


##
## ratings-v1 pod가 구동된 worker node에 ssh 접속하기
##

$ ssh root@node-73

##
## NOTE: worker node에 접속했으면, 위에서 알아냈던 container_id를 아래와 같이 설정하고
##       아래 명령 순서대로 실행한다.
##

[root@node-73 ~]$ container_id=6dbeeb047da9149f0735943cd95885a156dbdc766b48145c40e7346ea7f6bcfb

[root@node-73 ~]$ cpid=$(docker inspect --format '{{ .State.Pid }}' $container_id)


##
## Worker Node의 nsenter 명령을 이용하여 Container 내부의 iptables 정보를 조회한다.
##
[root@node-73 ~]$ nsenter -t $cpid -n iptables -L -t nat -n -v --line-numbers -x

Chain PREROUTING (policy ACCEPT 118222 packets, 7093320 bytes)
num      pkts      bytes target     prot opt in     out     source               destination
1      118224  7093440 ISTIO_INBOUND  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain INPUT (policy ACCEPT 118224 packets, 7093440 bytes)
num      pkts      bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 10650 packets, 924376 bytes)
num      pkts      bytes target     prot opt in     out     source               destination
1         400    24000 ISTIO_OUTPUT  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain POSTROUTING (policy ACCEPT 10650 packets, 924376 bytes)
num      pkts      bytes target     prot opt in     out     source               destination

Chain ISTIO_INBOUND (1 references)
num      pkts      bytes target     prot opt in     out     source               destination
1           0        0 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:15008
2           0        0 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:22
3           0        0 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:15090
4      118222  7093320 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:15021
5           0        0 RETURN     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            tcp dpt:15020
6           2      120 ISTIO_IN_REDIRECT  tcp  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain ISTIO_IN_REDIRECT (3 references)
num      pkts      bytes target     prot opt in     out     source               destination
1           2      120 REDIRECT   tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            redir ports 15006

Chain ISTIO_OUTPUT (1 references)
num      pkts      bytes target     prot opt in     out     source               destination
1           3      180 RETURN     all  --  *      lo      127.0.0.6            0.0.0.0/0
2           0        0 ISTIO_IN_REDIRECT  all  --  *      lo      0.0.0.0/0           !127.0.0.1            owner UID match 1337
3           0        0 RETURN     all  --  *      lo      0.0.0.0/0            0.0.0.0/0            ! owner UID match 1337
4         397    23820 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner UID match 1337
5           0        0 ISTIO_IN_REDIRECT  all  --  *      lo      0.0.0.0/0           !127.0.0.1            owner GID match 1337
6           0        0 RETURN     all  --  *      lo      0.0.0.0/0            0.0.0.0/0            ! owner GID match 1337
7           0        0 RETURN     all  --  *      *       0.0.0.0/0            0.0.0.0/0            owner GID match 1337
8           0        0 RETURN     all  --  *      *       0.0.0.0/0            127.0.0.1
9           0        0 ISTIO_REDIRECT  all  --  *      *       0.0.0.0/0            0.0.0.0/0

Chain ISTIO_REDIRECT (1 references)
num      pkts      bytes target     prot opt in     out     source               destination
1           0        0 REDIRECT   tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            redir ports 15001

[root@node-73 ~]$

 

 

위 iptables 구성에 관한 이론 및 개념 설명은 아래 blog를 참고하길~

 

 

iptables and netfilter

iptables의 Chain(Rule) & Table 구조 iptables는 다수의 Chain(예: PREROUTING, INPUT, OUTPUT, POSTROUTING, FORWARD)과 그 Chain에 정의된 Rule, 그리고 각 Chain에는 다수의 Table(raw, mangle, nat, filter,..

andrewpage.tistory.com

 

'kubernetes' 카테고리의 다른 글

Kubernetes Metrics Server 설치  (0) 2021.11.26
[TODO] Read - Istio Memo  (0) 2021.11.23
Kubernetes imagePullSecret 설정  (0) 2021.11.19
kubectl 명령 예제 & JSON 포맷으로 출력하기  (0) 2021.11.17
Setup Kubernetes Using Ansible  (0) 2021.11.15
반응형

 

작성일: 2024년 4월 29일

 

 

Keychron C1 키보드를 구입한지 3년이 지났다.

그 전에는 "Apple.com"에서 주문한 12만원짜리 Magic Keyboard(2021년형)을 사용했다.

두 제품의 타건감 차이는 극과 극이다.

이미 나는 기계식 키보드에 길들여져서인지, Magic Keyboard(매직 키보드)에 적응하지 못했다.

그리고 일반 기계식 키보드는 자판 배열이 맥북과 달라서 싫었다.

맥북과 자판 배열이 같고, 기계식 키보드(적축, 갈축 등)를 찾다보니 Keychron 제품이 눈에 들어왔다.

 

Keychron 제품에 관해서 궁금하다면 아래 웹 사이트를 방문하시길~~~

  https://keychron.kr 

 

 

간략하게 이 회사에 대해 설명하면;

 

Keychron은 2017년에 키보드 제조 분야에서 풍부한 경험을 가진 키보드 애호가 그룹에 의해 설립.

이 애호가 그룹은 디자이너, 마케터 및 생산 전문가로 구성됨.

핵심 팀원:

  - Will Ye: 키보드 생산 및 관련 비즈니스에서 9년의 경험을 가지고 있음

  - Sven Zhu: 산업 디자인에서 10년의 경험을 가지고 있음

이 회사는 미니멀한 디자인으로 가장 정교한 기계식 키보드를 만드는 것에 주력.

회사 주소: 

  • France Office:          1, Esplanade Miriam Makeba, 69100 Villeurbanne, France
  • Hong Kong Office:  13/F, Prosper Commercial Bldg., 9 Yin Chong Street, Kowloon, Hong Kong

 


키크론 키보드 타건샵

keychron.kr 홈페이지에 전국의 타건샵이 소개되어 있다.

서울, 경기도 쪽만 보면 아래 타겁샵이 있다.

 

  • 일렉트로마트 스타필드 수원점 (*) <-- 키크론 키보드 종류별로 있음. 데모 마우스 제품도 많음.
  • 일렉트로마트 스타필드 하남점 (*)
  • ---
  • 일렉트로마트 이마트 평촌점
  • 일렉트로마트 이마트 왕십리점
  • 일렉트로마트 이마트 영등포점
  • 일렉트로마트 이마트 성남점
  • ---
  • 일렉트로마트 오산점
  • 일렉트로마트 킨텍스점
  • 일렉트로마트 마포점
  • 더현대 서울 솔플레이점

 


사용 후기(리뷰)

나는 10년 전부터 5만원 대, 10만원 대, 20만원 대 기계식 키보드를 다양하게 사용하고 있었다.

지금도 사무실, 집에서 쓰고 있는 기계식 키보드는 4 종류이다.

그렇다면, 키크론(Keychron)에 대한 나의 평가는?

나의 답변: 만족한다!

 

기계식 키보드의 스위치 종류(제조사, 브랜드, 적/갈/흑/청축)에 따라 선호도가 다르기 때문에 [ 좋다, 고급지다, 저급하다 ]와 같은 평가를 하기는 거시기하고, 두루뭉술하게 키크론 키보드를 평가한다면 무난하게 평범한 기계식 키보드이다.

 

나는 Keychron Keyboard에 만족해서 우선 사무실에서 1개 구입하고, 1주일 후에 집에서 사용할 Keyboard를 한 개 더 구입했다.

지금은 사무실, 집에서 모두 Keychron Keyboard만 사용한다. (모두 적축으로 구입했음)

 

구입하고, 며칠 지난 후에 다시 Keychron Web site에 접속해보니, 레트로 버전을 새롭게 올렸던데... 솔직히 내 눈에는 레트로 키보드가 더 예뻐보인다.  한 달만 더 참았다 구입할껄하는 아쉬움이 남는다.

 

아주 솔직한 Keychron에 대한 내 생각은;

2021년 여름까지만 해도 비싸다는 인식만 있고, 품질이나 타건감은 5~10만원 정도의 기계식 키보드 수준이었다.

Apple 오프라인 매장에서 샘플 키보드를 사용해봐도, 이 정도의 키보드를 10만원 넘는 비용을 지불하면서 구입한다는 것은 미련한 짓이라 생각했는데...

2021년 가을부터 생각이 바뀌었다. 가격은 내려갔고, 품질은 더 좋아졌다. 특히 적축은 꽤 만족도가 높은 수준까지 왔다.

제품 가격을 생각해봐도 1년 전처럼 부담스럽지 않게 가격이 내려왔으니까, 주변 동료들이 구입한다고 하면... "추천!!!" 한다~~

반응형

`kubectl apply` 명령을 통해서 container image를 pull하려면, Docker 회사의 container image pulling에 대한 rate limit 정책 때문에 docker.io 또는 docker.com에서 image를 pulling하지 못하는 경우가 있다.

그래서 일반적으로 docker.com에 회원 가입하고, 무제한으로 image pulling 할 수 있도록 유료 서비스도 이용하는데, `docker login ....` 그리고 `docker image pull ...`하는 것은 잘 되지만, kubectl 명령으로 pod의 container image를 pulling하려면 rate limit제약이 있다. 바로 해당 Pod의 'imagePullSecret' 정보가 없이  때문이다. Pod가 생성될 때, Pod의 manifest에 있는 imagePullSecret 정보를 보고, Container Image Registry에 인증 요청을 하는 것인데 대부분 Pod manifest에 이 imagePullSecret 정보를 설정하지 않는다. (일부러 안 하는 것은 아니고, 이런 것이 있는 줄 모르니까 사용자들이 실수를 한다)

 

가장 흔한 Use Case가 namespace 마다 Docker Registry에 접속할 수 있는 secret을 등록하고, Pod manifest에 이 secret을 참조하도록 하는 것이다.  그런데 이것도 실제 사용하려면 문제가 있다. 내가 직접 작성한 Pod manifest라면, imagePullSecret을 추가하면 끝날 일이지만 istio처럼 istioctl 이라는 명령이 내부적으로 pod manifest를 생성해서 pod 생성을 시도하는 경우라면, imagePullSecret을 내 마음대로 추가하기 어렵다.

 

그래서~  나는 어떻게 이 문제를 풀어야 하지? ㅠㅠ

 

 

우선 즉흥적으로 생각나는 대로 메모를 해보면,  (깊게 생각한다고 풀릴 문제는 아닌 듯...)

  • Cluster 전체에서 공용으로 imagePullSecret을 사용할 수 있도록 설정하는 기능이 있는지 확인한다.
  • ServiceAccount에 Secret을 등록하고, 항상 이 ServiceAccount로 생성되는 Pod에 imagePullSecret을 사용할 수 있도록 한다.
  • istioctl 같은 별개의 deployment 관리 명령이 있는 경우라면, istioctl option 중에서 imagePullSecret을 설정하는 parameter가 있는지 찾아본다.

Web Docs를 잘 찾아보니까, 고맙게도 kubernetes.io의 Web Docs에 내가 고민하고 있는 내용을 잘 설명해주고 있다.

https://kubernetes.io/docs/concepts/containers/images/#using-a-private-registry

 

Images

A container image represents binary data that encapsulates an application and all its software dependencies. Container images are executable software bundles that can run standalone and that make very well defined assumptions about their runtime environmen

kubernetes.io

 

 

위 Web Docs에서는 아래의 4 가지 답안을 줬는데, 가장 사람 손을 덜 타는 (A) 방법으로 문제를 풀어봤다.

 

(A) Configuring Nodes to Authenticate to a Private Registry      ## 내가 선택한 해결 방법
    - all pods can read any configured private registries
    - requires node configuration by cluster administrator

(B) Pre-pulled Images
    - all pods can use any images cached on a node
    - requires root access to all nodes to setup

(C) Specifying ImagePullSecrets on a Pod
    - only pods which provide own keys can access the private registry

(D) Vendor-specific or local extensions
    - if you're using a custom node configuration,
       you (or your cloud provider) can implement your mechanism for authenticating the node to the container registry.

 

 

그래서 위 (A) 방법대로 문제를 해결했다~  자세한 절차는 아래 Web Docs에 있다.  단순하게 따라하면 잘 동작한다.


https://kubernetes.io/docs/concepts/containers/images/#configuring-nodes-to-authenticate-to-a-private-registry

위 원문을 조금 요약해보자면 아래와 같다.

##
## If you run Docker on your nodes, 
## you can configure the Docker container runtime to authenticate to a private container registry.
## This approach is suitable if you can control node configuration.

## Here are the recommended steps to configuring your nodes to use a private registry. 
## In this example, run these on your desktop/laptop PC:

##   1. Run docker login "docker.io" for each set of credentials you want to use. 
##      This updates $HOME/.docker/config.json on your PC.
##   2. View $HOME/.docker/config.json in an editor to ensure it contains only the credentials you want to use.
##   3. Get a list of your nodes; for example:
##     - if you want the names: 
##       nodes=$( kubectl get nodes -o jsonpath='{range.items[*].metadata}{.name} {end}' )
##     - if you want to get the IP addresses: 
##       nodes=$( kubectl get nodes -o jsonpath='{range .items[*].status.addresses[?(@.type=="ExternalIP")]}{.address} {end}' )
##   4. Copy your local .docker/config.json to one of the search paths list above.
##     - for example, to test this out: 
##       for n in $nodes; do scp ~/.docker/config.json root@"$n":/var/lib/kubelet/config.json; done
##

위 설명대로 /root/.docker/config.json 파일을 모든 master node, worker node의 /var/lib/kubelet/config.json 경로에 복사한 후에 아래와 같이 Pod를 deploy하면서  docker.io에서 rate limit이 걸리지 않고 container image를 pulling 할 수 있는지 확인한다. 

 

$  kubectl  apply -f -  <<EOF
apiVersion: v1
kind: Pod
metadata:
  name: busybox-sleep
spec:
  containers:
  - name: busybox
    image: busybox
    imagePullPolicy: Always
    args:
    - sleep
    - "1000000"
EOF

pod/busybox-sleep created

$ kubectl get pod
NAME            READY   STATUS    RESTARTS   AGE
busybox-sleep   1/1     Running   0          7s
$

 

주의:
나는 docker.io 유료 가입자이다.  이 글을 읽는 분도 본인이 사용하는 kubernetes cluster가 container image pulling rate limit 없이 동작하게 하려면 꼭 docker.io에 유료 가입해야 한다)

 

 

참고:

가장 일반적인 Use Case는 아래와 같이 namespace에 secret을 생성하고, 이 regcred 라는 secret을 Pod manifest에서 참조하도록 한다. 그런데, 모든 Pod의 manifest를 수정해야 하는 노동력이 추가되므로 이 방법을 권장하지 않는다.

(아마 imagePullSecret 정보를 자동으로 patch해주는 Mutating Admission Controller / WebHook Server를 만들어서 나의 Kubernetes Cluster에 추가해주면 사람이 개입할 일은 없겠지만, Webhook Server를 작성하는 것도 일인지라... ㅠㅠ)

 

$  kubectl create  -n ${MY-NS}  secret docker-registry  regcred  --docker-server=docker.io  --docker-username=${MYID}  --docker-password=${MYPW}

 

 

참고:

이 container image pulling rate limit 해결 방법은 순정 kubernetes cluster에서만 유효하고, Red Hat Openshift(OCP)는 Docker Registry 인증 문제를 해결하는 방식이 다르다. (결론만 말하자면, Red Hat OCP 쪽이 더 명령이 간단하고 쉽게 해결된다)

Red Hat에 비용을 내고 기술 지원 서비스를 받으면, Red Hat 직원이 알아서 해결해줬기 때문에 굳이 남의 밥벌이 영역의 일을 이렇게 공개된 글에 올리는 것은 예의가 아닌 것 같아서, Red Hat OCP에서의 Docker Registry 인증 문제에 대한 해결 방법은 언급하진 않겠다.

 

반응형

 

YAML 내용 비교하기 (using Python)

 

 

`vim -d old_file new_file` 또는 diff 등 명령으로 파일에서 변경된 내용을 확인할 수 있지만,

이렇게 비교를 하면, 내용이 동일하더라도 특정 내용의 행이 위/아래로 이동한 경우에는 다른 파일로 간주된다.

즉, 내용을 비교하고 싶은데 문서의 Format이 변경된 것 때문에 다른 파일로 인식되는 문제가 생긴다.

 

따라서 서로 다른 버전의 YAML file을 비교할 때는 두 파일을 Parsing해서 구조체에 넣고, 특정 항목이 추가되었는지 또는 삭제되었는지 또는 변경되었는지를 일일히 확인하는 것이 제일 정확한다.

 

Istio project의 Utility code를 살펴보니, 이런 기능을 하는 python code가 있어서 인용해봤다.

 

https://github.com/istio/istio/blob/master/bin/diff_yaml.py

 

GitHub - istio/istio: Connect, secure, control, and observe services.

Connect, secure, control, and observe services. Contribute to istio/istio development by creating an account on GitHub.

github.com

 

 

 

혹시 GitHub에서 Folder 구조가 바뀌거나 diff_yaml.py 도구가 제거될 것을 우려해서 여기 blog에 흔적을 남긴다.

 

diff_yaml.py (source code 열람)

#!/usr/bin/env python
#
# Copyright 2018 Istio Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Compare 2 multi document kubernetes yaml files
# It ensures that order does not matter
#
from __future__ import print_function
import argparse
import datadiff
import sys
import yaml  # pyyaml

# returns fully qualified resource name of the k8s resource


def by_resource_name(res):
    if res is None:
        return ""

    return "{}::{}::{}".format(res['apiVersion'],
                               res['kind'],
                               res['metadata']['name'])


def keydiff(k0, k1):
    k0s = set(k0)
    k1s = set(k1)
    added = k1s - k0s
    removed = k0s - k1s
    common = k0s.intersection(k1s)

    return added, removed, common


def drop_keys(res, k1, k2):
    if k2 in res[k1]:
        del res[k1][k2]


def normalize_configmap(res):
    try:
        if res['kind'] != "ConfigMap":
            return res

        data = res['data']

        # some times keys are yamls...
        # so parse them
        for k in data:
            try:
                op = yaml.safe_load_all(data[k])
                data[k] = list(op)
            except yaml.YAMLError as ex:
                print(ex)

        return res
    except KeyError as ke:
        if 'kind' in str(ke) or 'data' in str(ke):
            return res

        raise


def normalize_ports(res):
    try:
        spec = res["spec"]
        if spec is None:
            return res
        ports = sorted(spec['ports'], key=lambda x: x["port"])
        spec['ports'] = ports

        return res
    except KeyError as ke:
        if 'spec' in str(ke) or 'ports' in str(ke) or 'port' in str(ke):
            return res

        raise


def normalize_res(res, args):
    if not res:
        return res

    if args.ignore_labels:
        drop_keys(res, "metadata", "labels")

    if args.ignore_namespace:
        drop_keys(res, "metadata", "namespace")

    res = normalize_ports(res)

    res = normalize_configmap(res)

    return res


def normalize(rl, args):
    for i in range(len(rl)):
        rl[i] = normalize_res(rl[i], args)

    return rl


def compare(args):
    j0 = normalize(list(yaml.safe_load_all(open(args.orig))), args)
    j1 = normalize(list(yaml.safe_load_all(open(args.new))), args)

    q0 = {by_resource_name(res): res for res in j0 if res is not None}
    q1 = {by_resource_name(res): res for res in j1 if res is not None}

    added, removed, common = keydiff(q0.keys(), q1.keys())

    changed = 0
    for k in sorted(common):
        if q0[k] != q1[k]:
            changed += 1

    print("## +++ ", args.new)
    print("## --- ", args.orig)
    print("## Added:", len(added))
    print("## Removed:", len(removed))
    print("## Updated:", changed)
    print("## Unchanged:", len(common) - changed)

    for k in sorted(added):
        print("+", k)

    for k in sorted(removed):
        print("-", k)

    print("##", "*" * 25)

    for k in sorted(common):
        if q0[k] != q1[k]:
            print("## ", k)
            s0 = yaml.safe_dump(q0[k], default_flow_style=False, indent=2)
            s1 = yaml.safe_dump(q1[k], default_flow_style=False, indent=2)

            print(datadiff.diff(s0, s1, fromfile=args.orig, tofile=args.new))

    return changed + len(added) + len(removed)


def main(args):
    return compare(args)


def get_parser():
    parser = argparse.ArgumentParser(
        description="Compare kubernetes yaml files")

    parser.add_argument("orig")
    parser.add_argument("new")
    parser.add_argument("--ignore-namespace", action="store_true", default=False,
                        help="Ignore namespace during comparison")
    parser.add_argument("--ignore-labels", action="store_true", default=False,
                        help="Ignore resource labels during comparison")
    parser.add_argument("--ignore-annotations", action="store_true", default=False,
                        help="Ignore annotations during comparison")

    return parser


if __name__ == "__main__":
    parser = get_parser()
    args = parser.parse_args()
    sys.exit(main(args))

 

 

diff_yaml.py 명령 따라하기

위 python code를 diff_yaml.py 파일명으로 저장하고, 아래와 같이 필요한 Python package를 설치하고, Run 한다.

$  pip install --upgrade pip

$  python -m pip install datadiff

$  ./diff_yaml.py /tmp/metallb-1.yaml /tmp/metallb-2.yaml

## +++  /tmp/metallb-2.yaml
## ---  /tmp/metallb-1.yaml
## Added: 1
## Removed: 1
## Updated: 0
## Unchanged: 14
+ apps/v1::Deployment_Test::controller     ## 변경된 내용을 보여준다.
- apps/v1::Deployment::controller          ## 변경된 내용을 보여준다.
## *************************

$

## 이것은 Linux diff 명령으로 확인한 내용이다.
## 실제로 yaml 내용은 변경된 것이 1개 이지만, 단지 행을 이동했다는 이유만으로
## 여러 곳이 다르다고 표기하고 있다. (즉, YAML을 사용하는 User 관점에서 보면 다 쓸데 없는 정보이다.)

$  diff /tmp/metallb-1.yaml /tmp/metallb-2.yaml
3d2
< kind: Namespace             ## <-- 실제로 이 부분은 내용이 바뀐 것이 아니라, 라인만 이동한 것이다.
5d3
<   name: metallb-system      ## <-- 실제로 이 부분은 내용이 바뀐 것이 아니라, 라인만 이동한 것이다.
8a7,8
>   name: metallb-system      ## <-- 실제로 이 부분은 내용이 바뀐 것이 아니라, 라인만 이동한 것이다.
> kind: Namespace             ## <-- 실제로 이 부분은 내용이 바뀐 것이 아니라, 라인만 이동한 것이다.
352d351
< kind: Deployment
400a400
> kind: Deployment_Test       ## <-- 이 부분만 내용이 변경된 것이다.

 

위 결과를 보면, 일반적인 diff와 내용이 다르다는 것을 알 수 있다.

가장 큰 차이점은 diff_yaml.py는 수정된 Line과 Column을 출력하지 않는다. 왜냐하면, 내용 자체의 변경 여부가 관심사이지 어떤 내용이 다른 행으로 이동했는지 또는 삭제, 추가되었는지 중요하지 않기 때문이다.

 

 

 

JSON 내용 비교하기 (using Python)

 

JSON 내용을 비교하는 CLI 도구는 아래 Web Docs를 참고하길 ~~~

 

 

GitHub - xlwings/jsondiff: Diff JSON and JSON-like structures in Python

Diff JSON and JSON-like structures in Python. Contribute to xlwings/jsondiff development by creating an account on GitHub.

github.com

 

 

json-diff

Generates diff between two JSON files

pypi.org

 

 

반응형

Mac, Ubuntu, CentOS에서 Terminal을 사용하다보면, 알록달록 Color가 들어간 Text를 보게 된다.

이렇게 색이 들어간 글자를 만들려면, ANSI escape code라는 표준 기술을 활용해야 한다.

ANSI escape code에 관한 자세한 내용은 이 글의 끝 부분에 있는 Reference Web Docs를 보길~~~

 

간단하게 터미널의 글자에 색을 넣는 방법만 보면 아래와 같다.

 

Mac iTerm2 터미널에 글자 컬러 넣기

 

 

ANSI escape code 확인하는 C source code

각 ANSI code가 어떤 color, font, effect를 보여주는지 확인하고 싶다면, 아래와 같이 짧게 코드를 작성해서 돌려보면 바로 감(느낌)을 찾을 수 있다.

##
## File name:  main.c
##

#include <stdio.h>

int main(void)
{
  int i, j, n;

  for (i = 0; i < 11; i++) {
    for (j = 0; j < 10; j++) {
      n = 10*i + j;
      if (n > 108) break;
      printf("\033[%dm %3d\033[m", n, n);
    }
    printf("\n");
  }
  return 0;
}

 

위 C source code를 작성하고, 아래와 같이 gcc 명령으로 compile하고 실행해보면, 각 ANSI code의 숫자가 어떤 색을 표현하는지 알 수 있다.

 

ANSI escape code 확인하는 Python source code

각 ANSI code가 어떤 color, font, effect를 보여주는지 확인하고 싶다면, 아래와 같이 짧게 코드를 작성해서 돌려보면 바로 감(느낌)을 찾을 수 있다.

##
## File name:  main.py
##

import sys
for i in range(0, 16):
    for j in range(0, 16):
        code = str(i * 16 + j)
        sys.stdout.write(u"\u001b[38;5;" + code + "m " + code.ljust(4))
    print u"\u001b[0m"

 

위 Python source code를 작성하고, 아래와 같이 실행해보면, 각 ANSI code의 숫자가 어떤 색을 표현하는지 알 수 있다.

 

 

 

import sys
for i in range(0, 16):
    for j in range(0, 16):
        code = str(i * 16 + j)
        sys.stdout.write(u"\u001b[48;5;" + code + "m " + code.ljust(4))
    print u"\u001b[0m"

 

 

 

 

ANSI escape code의 역사, 표준 정보, Example 등 자세한 내용은 아래 Reference Web Docs를 참고하길 ~~~

 

Reference

 

ANSI escape code - Wikipedia

From Wikipedia, the free encyclopedia Jump to navigation Jump to search Method used for display options on video text terminals ANSI escape sequences are a standard for in-band signaling to control cursor location, color, font styling, and other options on

en.wikipedia.org

 

 

ASCII Art Archive

A large collection of ASCII art drawings and other related ASCII art pictures.

www.asciiart.eu

 

※ 아래 Web Docs는 CLI 만들기에 필요한 다양한 Trick과 Tip이 있다.

※ CLI에 Progress Bar, Processing Status, Percentile 등 효과를 넣고 싶다면 아래 Web Docs를 참고할 것 !!!

 

Build your own Command Line with ANSI escape codes

Build your own Command Line with ANSI escape codes Everyone is used to programs printing out output in a terminal that scrolls as new text appears, but that's not all your can do: your program can color your text, move the cursor up, down, left or right, o

www.lihaoyi.com

 

반응형

Mac OS의 iTerm2 터미널에서 한글 파일명을 작성하면, 아래 화면처럼 음소(자음, 모음)가 분리되면서 깨져 보이는 현상이 있다.

(자음, 모음 또는 초성, 중성, 종성이 분리되는 현상)

iterm2 설치 후, 아무런 설정을 하지 않고 기본 설정을 사용하면 이렇게 한글이 깨져 보인다.

한글 초성, 중성, 종성이 모두 분리되서 출력된다.

 

이 때,  iTerm2의 설정 화면을 보면 아래 화면처럼 [Unicode normalization form] 항목이 NFD로 되어 있을 것이다.

 

iTerm2 App의 [Preferences] / [Text] 설정

 

NFD를 다른 값으로 설정하면, 한글이 정상 모양으로 잘 출력된다. (아래 그림을 참고)

내 Macbook의 경우에는 [None, NFC, HFS+] 중에서 아무거나 선택해도 효과는 동일하게 잘 동작했다.

그런데, 다른 Mac User 중에서는  NFC만 잘 된다고 하는 User도 있는 걸로 봐서, 찜찜하면 NFC로 설정하는 것이 좋을 듯!!

 

iTerm2 App의 [Preferences] / [Text] 설정

 

한글 초성, 중성, 종성이 합쳐져서 보여진다.

 

Unicode normalization form을 NFD에서 NFC로 설정해서 잘 동작하니까 좋긴 한데, NFD, NFC가 무엇인지 잘 모르겠다.

NFD, NFC에 관한 자세한 설명은 아래 Web Docs를 참고하길 ~~~

 

Reference

 

 

유니코드 정규화(Unicode Normalization Form) 문제

 

www.hungrydiver.co.kr

 

+ Recent posts