-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsearch.xml
More file actions
1345 lines (649 loc) · 515 KB
/
search.xml
File metadata and controls
1345 lines (649 loc) · 515 KB
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title>안쓰는 노트북을 홈서버로 개조해보자 (feat. Windows를 밀고 Ubuntu Server 세팅하기)</title>
<link href="/2026/02/28/Tips/UbuntuServer-Setting/"/>
<url>/2026/02/28/Tips/UbuntuServer-Setting/</url>
<content type="html"><![CDATA[<p>동생이 집에 홈서버 있으면 쓰고싶다 하길래 굳이 필요한가 싶어 빠꾸시켰는데, 생각을 해보니 하나 장만하면 동생이 컴퓨터 공부를 하는데 제격이겠다 싶어서 오랜만에 만들어봤다.</p><p>나는 집에서 안쓰는, 2017년인가에 구매한 삼성의 always9 노트북으로 홈서버를 만들었다.</p><h2 id="0-준비물"><a href="#0-준비물" class="headerlink" title="0. 준비물"></a>0. 준비물</h2><ul><li>Ubuntu Server 이미지를 구울 <strong>USB</strong></li><li>안쓰는 노트북 (여기서는 삼성 always9 사용)</li><li>사용 중인 노트북 (ubuntu server와의 통신을 위함)</li></ul><h2 id="1-Ubuntu-Server-이미지-다운로드"><a href="#1-Ubuntu-Server-이미지-다운로드" class="headerlink" title="1. Ubuntu Server 이미지 다운로드"></a>1. Ubuntu Server 이미지 다운로드</h2><ul><li>사이트: <a href="https://ubuntu.com/download/server">https://ubuntu.com/download/server</a></li></ul><p>일단 홈서버는, 컴퓨터가 계속 돌아간다는 가정이 있어야 하기 때문에 <strong>에너지를 가장 안 잡아먹는</strong>형태로 구현을 해야한다.</p><p>우리가 생각하는 우분투 데스크톱은 GUI가 있어 CPU, RAM같은 컴퓨터 자원을 많이 잡아먹기 때문에, 아주 최소한의 필수 기능만 들어있는 <strong>Ubuntu Server</strong>를 사용했다.</p><p>애초에 ubuntu server는 SSH를 통해 명령어를 입력하는 방식이 최적화되어 있기도 하고, attack surface도 적어서 다른 것들에 비해 매우 안전한 편이기도 하다.</p><p>다들 알겠지만 프로그램은 <strong>LTS</strong>버전이 가장 안정적이다!</p><h2 id="2-USB에-이미지-굽기"><a href="#2-USB에-이미지-굽기" class="headerlink" title="2. USB에 이미지 굽기"></a>2. USB에 이미지 굽기</h2><p>그냥 파일을 담으면 안된다. iso로 다운받아질텐데, 이거를 노트북에 꽂았을 때 <strong>부팅이 가능한 상태</strong>로 만들어야 한다.</p><p>그래서 windows를 사용 중이라면 <a href="https://rufus.ie/ko/">Rufus</a>를, 맥북을 사용 중이라면 <a href="https://etcher.balena.io/">BalenaEtcher</a>를 이용해서 usb를 구워준다.</p><h2 id="3-노트북에서-부팅-설정-잡기"><a href="#3-노트북에서-부팅-설정-잡기" class="headerlink" title="3. 노트북에서 부팅 설정 잡기"></a>3. 노트북에서 부팅 설정 잡기</h2><p>USB를 구웠다면, 이제 ubuntu server를 설치할 노트북의 부팅 설정을 잡아줘야 한다. 그래야 usb를 선택해서 기존의 환경을 싹 다 밀고 ubuntu server를 설치할 수 있기 때문이다.</p><p>노트북마다 전원키가 다를 수 있는 점을 참고하길 바라며, 여기서는 삼성 always9 세팅으로 설명을 적어본다.</p><ul><li>전원이 켜지자마자 <code>F2</code>를 연타하여 삼성 BIOS 설정 화면으로 들어간다.</li><li>필자의 기억이 정확히 안나서 해당 메뉴이 명확한지 확신이 안들지만 일단 이런 느낌의 항목을 찾을 수 있을 것이다. BIOS에서 아래의 세팅이 잘 되어 있는지 확인해보자<ul><li>Secure Boot (Control): Off 또는 Disabled</li><li>OS Mode Selection: UEFI가 들어있는 메뉴로 변경</li><li>Fast BIOS Mode: Off</li><li>Battery Life Extender+: On</li><li>USB S3 Wakeup: On</li></ul></li><li>위 설정을 완료했다면 Save를 한 후, 재부팅을 하자마자 다시 F2를 연타하자</li></ul><h2 id="4-Ubuntu-Server-설치하기"><a href="#4-Ubuntu-Server-설치하기" class="headerlink" title="4. Ubuntu Server 설치하기"></a>4. Ubuntu Server 설치하기</h2><p>여기까지 잘 됐다면, <code>Try or install Ubuntu Server</code>, <code>Ubuntu server with the hwe kernel....</code> 이라는 선택지가 나올 것이다.</p><p>여기에서 맨 위의 <code>Try or install Ubuntu Server</code>를 Enter로 선택하거나, 아니면 가만히 있음 알아서 Ubuntu Server 설치로 이동하게 될 것이다.</p><p>그렇게 1분 정도 기다리면 영어가 올라오면서, 기본 세팅이 되는 것을 확인할 수 있다.</p><ul><li>Language: English 선택 (한글 지원 안됨)</li><li>Network: 일단 나중에 설정할 예정이니 바로 Done으로 넘어가기</li><li>Storage Configuration: <code>Use an entire disk</code>를 선택하면 기존의 프로그램 및 파일들이 싹다 없어진다. 그리고 <code>Done</code>을 누르면 <code>Confirm destructive action</code>이 나오는데, <code>Continue</code>를 선택하면 이 순간 Windows OS와 영원한 작별인사를 하게 된다는 점을 알아두자</li><li>Profile Setup<ul><li>Your name: 본인 이름</li><li>Your server’s name: 서버 이름</li><li>Pick a username: 로그인 아이디</li><li>Password: 비밀번호</li></ul></li></ul><p>이 모든 세팅이 완료된다면, <code>Install complete</code>가 나오고 <code>Reboot Now</code>가 나오는데, Reboot now를 누른 후 바로 꽂혀있는 USB를 제거한다.</p><p>설치가 잘됐다면 <code>end ssh host keys...</code> <code>datasource datasourceone up xxx seconds</code>라고 하면서 무한커서가 나오는데, 세팅이 잘 됐다는 의미이다.</p><p>이 때 엔터를 한두번 하면 <code>login:</code>이라며 커서가 깜빡이는데, <code>Pick a username</code>에 입력했던 아이디를 입력, 엔터 후 password도 잘 입력을 하면 서버 로그인에 성공할 것이다.</p><h2 id="5-노트북-뚜껑-닫기-설정-Lid-Switch-설정"><a href="#5-노트북-뚜껑-닫기-설정-Lid-Switch-설정" class="headerlink" title="5. 노트북 뚜껑 닫기 설정 (Lid Switch 설정)"></a>5. 노트북 뚜껑 닫기 설정 (Lid Switch 설정)</h2><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">sudo</span> <span class="token function">vim</span> /etc/systemd/logind.conf</code></pre><p>아래 항목들을 다음같이 변경해준다.</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token assign-left variable">HandleLidSwitch</span><span class="token operator">=</span>ignore<span class="token assign-left variable">HandleLidSwitchExternalPower</span><span class="token operator">=</span>ignore<span class="token assign-left variable">HandleLidSwitchDocked</span><span class="token operator">=</span>ignore</code></pre><p>이후 변경사항을 적용해준다.</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">sudo</span> systemctl restart systemd-logind</code></pre><p>이 세팅을 해주면 노트북 뚜껑을 닫아도 프로그램이 계속 작동되는걸 볼 수 있을 것이다.</p><h2 id="6-와이파이-Wi-Fi-잡기"><a href="#6-와이파이-Wi-Fi-잡기" class="headerlink" title="6. 와이파이 Wi-Fi 잡기"></a>6. 와이파이 Wi-Fi 잡기</h2><p>외부와의 통신을 위해 와이파이를 잡아줘야 한다.</p><p>ubuntu server는 <code>netplan</code>이라는 도구를 이용해 네트워크를 관리해준다.</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">ip</span> <span class="token function">link</span></code></pre><p>위 명령어를 입력하면, <code>wlp...</code>로 시작하는 이름이 보일 것이다. (대부분 이름이 <strong>wlp1s0</strong>임)</p><p>이 이름을 잘 백업해놓자. 이후로 설정 파일을 만들어서 wifi 연결을 잡아줄 것이다.</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">sudo</span> <span class="token function">vim</span> /etc/netplan/01-netcfg.yaml</code></pre><p>파일 내용은 다음과 같이 만들어준다.<br>참고로 <code>.</code>하나가 스페이스바 한 번이니, 형식에 맞춰서 잘 작성을 할 것을 권장한다. 의외로 여기에서 오류가 굉장히 많이 나더라;</p><pre class="language-bash" data-language="bash"><code class="language-bash">network:<span class="token punctuation">..</span>version: <span class="token number">2</span><span class="token punctuation">..</span>renderer: networkd<span class="token punctuation">..</span>wifis:<span class="token punctuation">..</span><span class="token punctuation">..</span>wlp1s0: <span class="token comment"># 아까 백업하라고 했던 네트워크 이름</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span>dhcp4: <span class="token function">yes</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span>access-points:<span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token string">"와이파이이름"</span><span class="token builtin class-name">:</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span><span class="token punctuation">..</span>password: <span class="token string">"비밀번호"</span></code></pre><p>이후, 파일의 권한을 소유자만 읽고 쓸 수 있게 변경해준다.</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">sudo</span> <span class="token function">chmod</span> <span class="token number">600</span> /etc/netplan/01-netcfg.yaml</code></pre><p>이 변경사항을 적용한다. 그러면 인터넷이랑 연결이 될 것이다.</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">sudo</span> netplan apply</code></pre><p>만약에 인터넷 연결을 확인하고 싶다면, 다음의 명령어를 입력하면 된다.</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">ping</span> <span class="token parameter variable">-c</span> <span class="token number">3</span> google.com</code></pre><p>핑이 3번 잘 와리가리 했다면, 인터넷이 잘 통한다는 의미이다. 만약 “Temporary failure in name resolution….”같은 문장이 나오면 띄어쓰기나 와이파이 이름, 비밀번호 오타일 수 있으니 꼭 확인해보자</p><h2 id="7-IP-확인하기"><a href="#7-IP-확인하기" class="headerlink" title="7. IP 확인하기"></a>7. IP 확인하기</h2><p>홈서버는 만들어졌다. 근데 주소를 알아야 와리가리를 할 수 있기 때문에, IP를 꼭 알아내야 한다.</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">ip</span> addr show wlp1s0</code></pre><p>위 명령어를 입력하면, 어떤 내용들이 쫙 나오는데 여기에서 <code>inet</code>다음에 나오는 숫자를 확인하면 된다.<br><br>보통은 <code>192.168.0.xxx</code> 또는 <code>172.x.x.x</code>형식으로 나올 것이다.</p><h2 id="8-다른-컴퓨터에서-홈서버-연결해보기"><a href="#8-다른-컴퓨터에서-홈서버-연결해보기" class="headerlink" title="8. 다른 컴퓨터에서 홈서버 연결해보기"></a>8. 다른 컴퓨터에서 홈서버 연결해보기</h2><p>이제 모든 준비는 끝났다. 홈서버에 직접 접속을 확인해보자</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">ssh</span> <span class="token string">"Pick a username에 입력했던 값"</span>@<span class="token string">"서버IP주소"</span> <span class="token comment"># 예: ssh systemadmin@192.168.0.1</span></code></pre><p>맨 처음 접속하면 Are you sure you want to continue connecting? 이라는 문구가 나오는데, 바로 yes를 타이핑한다. 그러면 비밀번호를 입력하라는데, 비밀번호를 입력하면 로그인이 잘 될 것이다.</p><img src="/2026/02/28/Tips/UbuntuServer-Setting/1.png" class="" title="unbutu server 접속 결과물"><p><br><br><br></p><p>저기에서 자원을 효율적으로 관리하고 싶은 사람들은 k8s를 세팅해서 운영하면 된다.</p><p>세팅법 다 까먹은 줄 알았는데 아주 잘된다 좋아요~~</p>]]></content>
<categories>
<category> 💾 Etc </category>
</categories>
<tags>
<tag> Ubuntu </tag>
<tag> Windows </tag>
</tags>
</entry>
<entry>
<title>Kubernetes 용어 완전 쉽게 이해하기</title>
<link href="/2026/02/28/DevOps/K8S-Easy/"/>
<url>/2026/02/28/DevOps/K8S-Easy/</url>
<content type="html"><![CDATA[<p>요즘 프로젝트 멘토링에서 K8S 수업을 하고 있는데, 다들 용어 습득에 매우 어려움을 겪으시더라… 그래서 <strong>아주 완전 쉽게</strong> 이해하실 수 있도록 준비해본게 나름 괜찮은 것 같아서 ^_^ 블로그 글로 한 번 남겨본다.</p><p>모든 개념이 들어있진 않으니 참고하세요</p><h2 id="1-Node-노드"><a href="#1-Node-노드" class="headerlink" title="1. Node 노드"></a>1. Node 노드</h2><p>여러분들 앞에 10년도 더 된, 사용하지 않는 고물 노트북이 있다고 가정해보자.</p><p>이거를 여러분들의 <strong>홈서버</strong>로 설정하여 프로그램을 돌리거나 gdrive같은 <strong>파일저장시스템</strong>을 만든다고 하자. 그리고 여러분들은 가족들 모두가 이용할 수 있도록 설정을 세분화 하고 싶다고 하자.</p><p>이 때 여러분들이 <strong>K8S</strong>로 시스템을 관리한다고 하면, node는 <strong>실제 물리적 공간 = 노트북</strong>이 된다.</p><p>그 중에서도</p><ul><li><strong>Master Node</strong>: 직접 일은 안하고 명령만 내리는 일종의 <strong>두뇌</strong> (예시에서는 노트북이 두뇌 역할을 겸하는 중)</li><li><strong>Worker Node</strong>: 쫄따구(Pod)가 실제로 거주하며 일하는 <strong>물리적 공간</strong>을 의미한다.</li></ul><h2 id="2-Namespace-네임스페이스"><a href="#2-Namespace-네임스페이스" class="headerlink" title="2. Namespace 네임스페이스"></a>2. Namespace 네임스페이스</h2><p>Namespace는 가상 구역을 나눌 때 사용한다. 즉 <strong>Node를 가상으로 N등분 한거</strong>라고 이해하면 된다.</p><p>노트북에서 A, B, C라는 Namespace(=구역)을 나누면 가족 1, 가족 2, 가족 3이 각각의 영역을 사용하면 된다는 얘기다.</p><p>분명 서버 테스트를 한다고 이것저것 돌려보면 오류가 날 가능성이 있다. 이 때 namespace를 기준으로 세팅을 하면 서로의 영역을 터치하지 않기 때문에 다른 쪽에서 에러가 났다한들 다른 프로그램은 잘 돌아가는걸 볼 수 있다.</p><h2 id="3-Pod-파드"><a href="#3-Pod-파드" class="headerlink" title="3. Pod 파드"></a>3. Pod 파드</h2><p>실제 이 체계에서 가장 <strong>쫄따구 / 노예</strong> 계급이라고 생각하면 된다. 얘가 실무 처리를 다 한다.</p><p>여기서 시스템 서버 돌리기 등이 일어난다.</p><p>만약 서비스에 사람들이 많이 들어온다? 그러면 일이 바쁘단 얘기가 되는 것이며, 그럼 노예를 더 뽑아서 일을 시켜야 한다는 의미가 되므로 Pod들이 우후죽순 여러 개가 생겨난다고 보면 된다.</p><p>반대로 서비스에 사람들이 줄어들었다, 그러면 필요없는 Pod들이 삭제된다.</p><p>즉, <strong>Pod들은 추가되거나 삭제되는 것에서 매우 자유롭다고 생각하면 된다.</strong> <del>마치 회사 인원감축 때 가장 잘리기 쉬운 말단사원처럼……</del></p><h2 id="4-Service-서비스"><a href="#4-Service-서비스" class="headerlink" title="4. Service 서비스"></a>4. Service 서비스</h2><p>현실세계에서 다른 집으로 이사를 갔다고 쳐보자. 집 주소는 바뀌겠지만 자신의 핸드폰 번호는 번호 변경 서비스 신청을 하지 않는 이상 <strong>그대로일 것이다</strong>.</p><p>앞서 <strong>Pod는</strong> 추가/삭제에 매우 자유롭다고 말했는데, 이 얘기는 바로 노예의 정보가 자주 바뀐다는 의미 = <strong>주소가 고정되어 있지 않다</strong>는 뜻이 된다.</p><p>우리 입장에서는 이 Pod에서 원하는 서버를 돌리는건데, 이걸 못찾는다? 그러면 이걸 매번 어디있는지 찾아서 돌아가라! 라고 명령을 내려야 하는게 여간 귀찮은 일이 아니다. 이 때 나오는 개념이 바로 <strong>Service</strong>이다.</p><p>Service를 사용하면 <strong>주소를 고정</strong>함으로써 Pod의 내용물이 바뀌더라도 알아서 변경 주소로 매핑이 되어 우리가 편하게 이용할 수 있다.</p><h2 id="5-Port-포트"><a href="#5-Port-포트" class="headerlink" title="5. Port 포트"></a>5. Port 포트</h2><p>보통의 회사같은 경우 마케팅 / IT / HR / 경영 부서가 각각 있을 것이다. 회사다보니 사람들이 이직 또는 퇴사를 하면서 인원변동이 있을 것이지만, 부서 자체는 사라지는 일이 거의 없다.</p><p>여기 k8s에서도 마찬가지다. 어쨌든간에 관리직이든 노예든 모두가 일을 할텐데, 현실세계에서 우리가 이직이나 퇴사를 하는 것처럼 얘들이 평생을 바쳐 일을 하지 않는다. 자원이 변경될 수 있다. 하지만 자원들이 <strong>속한 공간은 변경되지 않는다</strong>.</p><p>그래서 Port는 <strong>실제 일하는 공간의 주소</strong>라고 생각하면 된다.</p><ul><li>targetPort: Pod들이 실제로 머무는 주소 - 101동 101호같은 주소에서 <strong>101호</strong>를 의미</li><li>port: 서비스의 주소 - 여러 개의 서비스가 있으니 “A 서비스는 80번”, “B 서비스는 81번” 식으로 이름을 붙여줌</li><li>nodePort: 외부에서 노트북(Node) IP를 치고 들어올 때 쓰는 일종의 <strong>정문 번호</strong></li></ul><h2 id="6-Deployment-ReplicaSet"><a href="#6-Deployment-ReplicaSet" class="headerlink" title="6. Deployment / ReplicaSet"></a>6. Deployment / ReplicaSet</h2><p>위에서 pod들이 실질적인 일을 한다고 했는데, 여기서 deployment와 replicaSet은 그 pod들의 상사 역할이라고 생각하면 된다.</p><p>즉 <strong>Deployment > ReplicaSet > Pod</strong> 순이며,</p><ul><li>Deployment가 “새 버전 업데이트”, “롤백” 같은 <strong>전체적인 전략</strong>을 짜면</li><li>ReplicaSet이 Deployment의 명령을 받고 <strong>오직 Pod의 숫자 관리</strong>에 집중을 한다. 예를 들면 “지금 바빠 죽겠는데 pod가 하나네? 더 만들자” 이런식으로 된다.</li><li>그리고 실질적으로 Pod가 그 일을 한다고 생각하면 된다.</li></ul><p>그래서 실제로 명령어를 쳐보면,</p><ul><li>Deployment: my-web</li><li>ReplicaSet: my-web-123abc</li><li>Pod: my-web-random-123abc-def456</li></ul><p>이런식으로 종속되어 있는 형태로 이름이 지어지는 것을 알 수 있다.</p><h2 id="7-Ingress-Egress"><a href="#7-Ingress-Egress" class="headerlink" title="7. Ingress / Egress"></a>7. Ingress / Egress</h2><p>위에서 우리는 port라는 것을 설명했는데, port는 쉽게 “주소”를 얘기한다고 했다.</p><p>만약에 노트북을 홈서버로 만들었다고 하면, 보통은 공부 목적으로 프로젝트를 만들어 배포 연습도 할 것이다.</p><p>근데 그런 프로젝트가 한 두개여도 포트 번호를 외우는데 귀찮은데, 이게 20개 30개가 넘는다고 하자. 이걸 언제 다 외우겠는가??</p><p>이 때 필요한게 바로 <strong>Ingress</strong>이다. Ingress는 <strong>포트 번호를 외우기 싫을 때, 도메인에 연결해서 쉽게 우리의 포트와 매핑을 해주는 것</strong>이라고 생각하면 된다.</p><br><p>그럼 <strong>Egress</strong>는 무엇이냐, 일단 Ingress는 영단어만 보면 “들어온다”는 뜻이다. 즉 Egress는 그 반대로 “밖으로 나가는 것”에 대한 것이 된다.</p><p>그럼 데이터가 밖으로 나가는 경우가 무엇이 있을까? 보통은 사용자가 서버에서 데이터를 다운로드받을 때를 생각하겠지만, 여러 관점에서 생각해볼 때 <strong>해킹당했을 때 데이터가 밖으로 나갈 것</strong>도 고려해야 한다.</p><p>그래서 Egress는 <strong>데이터를 밖으로 꺼낼 때 얼마나 차단할지</strong>를 설정해서, 해킹 방지용에 많이 사용한다고 생각하면 된다.</p><h2 id="8-Volume"><a href="#8-Volume" class="headerlink" title="8. Volume"></a>8. Volume</h2><p>지금까지는 프로그램에 대한 얘기를 했다. pod를 통해 실질적으로 프로그램을 돌린다고 했는데, pod는 결국 노예이기 때문에 필요 없으면 바로 컷을 당하는 불쌍한 아이다.</p><p>그러면 이 얘기는 즉슨, pod가 사라지면 기존에 pod 안에 있던 데이터는 전부 하늘나라로 날아가게 된다는 얘기다. 우리의 데이터는 그럼 영원한 이별을 맞이하게 된다는 그런 슬픈 이야기가….</p><p>그럼 데이터를 안날아가게 하는 방법이 있냐? 당연히 있다. 이 때 나오는 개념이 바로 <strong>Volume</strong>이다.</p><p>Volume을 사용하면 <strong>하드디스크에 데이터를 안전하게 저장해서 영구 보관을 할 수 있다.</strong></p><p>노트북으로 서버를 만들었다면, 이 노트북의 하드디스크게 데이터를 저장하게 될 것이다.</p><p>우리는 이것을 <strong>PV(Persistent Volume)</strong> 이라고 부르며, 파일을 저장하고 관리하는 경험을 하고 싶을 때 <strong>PVC(Persistent Volume Claim)</strong> 이라는 저장소 요청소를 만들어서 k8s에 제출하면 파일을 업로드할 수 있다.</p>]]></content>
<categories>
<category> ♼ DevOps </category>
</categories>
<tags>
<tag> DevOps </tag>
<tag> Kubernates </tag>
</tags>
</entry>
<entry>
<title>[HealthCare] HL7 FHIR 완전 정리</title>
<link href="/2025/08/25/HealthCare/HL7/fhir/"/>
<url>/2025/08/25/HealthCare/HL7/fhir/</url>
<content type="html"><![CDATA[<h2 id="HL7-FHIR-완전-정리"><a href="#HL7-FHIR-완전-정리" class="headerlink" title="HL7 FHIR 완전 정리"></a>HL7 FHIR 완전 정리</h2><p>헬스데이터 스타트업이라면 <strong>FHIR</strong>은 반드시 이해해야 할 표준이다.<br>FHIR(Fast Healthcare Interoperability Resources)는 HL7이 v2, v3, CDA의 교훈을 바탕으로 만든 최신 국제 표준이다.</p><hr><h3 id="1-FHIR이란"><a href="#1-FHIR이란" class="headerlink" title="1. FHIR이란?"></a>1. FHIR이란?</h3><ul><li>풀네임: <strong>Fast Healthcare Interoperability Resources</strong></li><li>HL7이 2014년부터 개발한 차세대 표준 (현재 R5까지 출시)</li><li>웹/모바일 친화적인 설계를 목표로 함</li><li>JSON, XML, RDF 형식 지원 (주로 JSON 사용)</li><li>REST API, GraphQL, 메시징 등 다양한 통신 방식 지원</li></ul><hr><h3 id="2-왜-FHIR인가"><a href="#2-왜-FHIR인가" class="headerlink" title="2. 왜 FHIR인가?"></a>2. 왜 FHIR인가?</h3><ul><li><strong><a href="/2025/02/20/HealthCare/HL7/v2/" title="[HealthCare] HL7 v2 정리">v2</a> → 단순하지만 병원마다 제각각</strong></li><li><strong><a href="/2025/03/05/HealthCare/HL7/v3/" title="[HealthCare] HL7 v3의 실패 이유 정리">v3</a> → 구조적이지만 너무 복잡해서 실패</strong></li><li><strong><a href="/2025/08/02/HealthCare/HL7/cda/" title="[HealthCare] HL7 CDA 표준 정리">CDA</a> → 문서 교환에는 성공했지만 실시간 데이터 교환 한계</strong></li></ul><p>➡️ FHIR은 이 모든 문제를 개선했다.</p><ul><li>직관적인 JSON 구조</li><li>리소스(Resource) 단위 설계 (Patient, Observation, Encounter 등)</li><li>RESTful API로 쉽게 통신 가능</li><li>Implementation Guide(IG), 프로파일링/검증 도구 제공</li></ul><hr><h3 id="3-FHIR-리소스-Resource"><a href="#3-FHIR-리소스-Resource" class="headerlink" title="3. FHIR 리소스(Resource)"></a>3. FHIR 리소스(Resource)</h3><p>FHIR의 핵심은 <strong>리소스(Resource)</strong> 개념이다.<br>각각의 리소스가 의료 개념(환자, 진단, 검사 결과 등)을 표현한다.</p><p>대표적인 리소스:</p><ul><li><strong>Patient</strong> : 환자 정보</li><li><strong>Observation</strong> : 검사 결과, 활력징후</li><li><strong>Encounter</strong> : 진료/입원 방문</li><li><strong>Condition</strong> : 진단명</li><li><strong>MedicationRequest</strong> : 처방</li><li><strong>DocumentReference</strong> : 문서 (CDA와 연결됨)</li></ul><hr><h3 id="4-FHIR-JSON-예시"><a href="#4-FHIR-JSON-예시" class="headerlink" title="4. FHIR JSON 예시"></a>4. FHIR JSON 예시</h3><h4 id="4-1-Patient-리소스"><a href="#4-1-Patient-리소스" class="headerlink" title="4-1) Patient 리소스"></a>4-1) Patient 리소스</h4><pre class="language-json" data-language="json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"resourceType"</span><span class="token operator">:</span> <span class="token string">"Patient"</span><span class="token punctuation">,</span> <span class="token property">"id"</span><span class="token operator">:</span> <span class="token string">"12345"</span><span class="token punctuation">,</span> <span class="token property">"name"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token property">"family"</span><span class="token operator">:</span> <span class="token string">"Kim"</span><span class="token punctuation">,</span> <span class="token property">"given"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"Minjun"</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"gender"</span><span class="token operator">:</span> <span class="token string">"male"</span><span class="token punctuation">,</span> <span class="token property">"birthDate"</span><span class="token operator">:</span> <span class="token string">"1990-01-01"</span><span class="token punctuation">,</span> <span class="token property">"address"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token property">"city"</span><span class="token operator">:</span> <span class="token string">"Seoul"</span><span class="token punctuation">,</span> <span class="token property">"country"</span><span class="token operator">:</span> <span class="token string">"KR"</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"telecom"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token property">"system"</span><span class="token operator">:</span> <span class="token string">"phone"</span><span class="token punctuation">,</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token string">"010-1234-5678"</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">}</span></code></pre><h4 id="4-2-Observation-리소스-혈압"><a href="#4-2-Observation-리소스-혈압" class="headerlink" title="4-2) Observation 리소스 (혈압)"></a>4-2) Observation 리소스 (혈압)</h4><pre class="language-json" data-language="json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"resourceType"</span><span class="token operator">:</span> <span class="token string">"Observation"</span><span class="token punctuation">,</span> <span class="token property">"id"</span><span class="token operator">:</span> <span class="token string">"bp-001"</span><span class="token punctuation">,</span> <span class="token property">"status"</span><span class="token operator">:</span> <span class="token string">"final"</span><span class="token punctuation">,</span> <span class="token property">"category"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token property">"coding"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token property">"system"</span><span class="token operator">:</span> <span class="token string">"http://terminology.hl7.org/CodeSystem/observation-category"</span><span class="token punctuation">,</span> <span class="token property">"code"</span><span class="token operator">:</span> <span class="token string">"vital-signs"</span> <span class="token punctuation">}</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token property">"code"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"coding"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token property">"system"</span><span class="token operator">:</span> <span class="token string">"http://loinc.org"</span><span class="token punctuation">,</span> <span class="token property">"code"</span><span class="token operator">:</span> <span class="token string">"85354-9"</span><span class="token punctuation">,</span> <span class="token property">"display"</span><span class="token operator">:</span> <span class="token string">"Blood pressure panel"</span> <span class="token punctuation">}</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"subject"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"reference"</span><span class="token operator">:</span> <span class="token string">"Patient/12345"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"effectiveDateTime"</span><span class="token operator">:</span> <span class="token string">"2025-08-26T10:30:00+09:00"</span><span class="token punctuation">,</span> <span class="token property">"component"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"code"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"coding"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token property">"system"</span><span class="token operator">:</span> <span class="token string">"http://loinc.org"</span><span class="token punctuation">,</span> <span class="token property">"code"</span><span class="token operator">:</span> <span class="token string">"8480-6"</span><span class="token punctuation">,</span> <span class="token property">"display"</span><span class="token operator">:</span> <span class="token string">"Systolic blood pressure"</span> <span class="token punctuation">}</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"valueQuantity"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token number">120</span><span class="token punctuation">,</span> <span class="token property">"unit"</span><span class="token operator">:</span> <span class="token string">"mmHg"</span><span class="token punctuation">,</span> <span class="token property">"system"</span><span class="token operator">:</span> <span class="token string">"http://unitsofmeasure.org"</span><span class="token punctuation">,</span> <span class="token property">"code"</span><span class="token operator">:</span> <span class="token string">"mm[Hg]"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"code"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"coding"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token property">"system"</span><span class="token operator">:</span> <span class="token string">"http://loinc.org"</span><span class="token punctuation">,</span> <span class="token property">"code"</span><span class="token operator">:</span> <span class="token string">"8462-4"</span><span class="token punctuation">,</span> <span class="token property">"display"</span><span class="token operator">:</span> <span class="token string">"Diastolic blood pressure"</span> <span class="token punctuation">}</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"valueQuantity"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token number">80</span><span class="token punctuation">,</span> <span class="token property">"unit"</span><span class="token operator">:</span> <span class="token string">"mmHg"</span><span class="token punctuation">,</span> <span class="token property">"system"</span><span class="token operator">:</span> <span class="token string">"http://unitsofmeasure.org"</span><span class="token punctuation">,</span> <span class="token property">"code"</span><span class="token operator">:</span> <span class="token string">"mm[Hg]"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">}</span></code></pre><hr><h3 id="5-FHIR의-장점"><a href="#5-FHIR의-장점" class="headerlink" title="5. FHIR의 장점"></a>5. FHIR의 장점</h3><ul><li><strong>현대적 개발환경과 친화적</strong>: REST API, JSON, GraphQL 지원</li><li><strong>모듈성</strong>: 필요한 리소스만 조합해 사용</li><li><strong>프로파일링</strong>: 각 나라/기관이 자신만의 Implementation Guide(IG)를 정의 가능</li><li><strong>검증 도구 풍부</strong>: IG Publisher, HAPI-FHIR, Firely 등</li><li><strong>상호운용성 확보</strong>: 코드 체계(LOINC, SNOMED CT 등)와 연계</li></ul><hr><h3 id="6-실제-활용-사례"><a href="#6-실제-활용-사례" class="headerlink" title="6. 실제 활용 사례"></a>6. 실제 활용 사례</h3><ul><li><strong>미국 ONC/Meaningful Use</strong>: FHIR을 국가적 표준으로 지정</li><li><strong>애플 HealthKit</strong>: FHIR 기반 API로 병원과 데이터 연동</li><li><strong>Google Cloud Healthcare API, Microsoft Azure Health Data Services</strong>: 클라우드 벤더들이 FHIR API 기본 제공</li><li><strong>대한민국</strong>: 보건복지부 주도로 국가 EHR·PHR 사업에서 FHIR 채택 확산 중</li></ul><hr><h3 id="7-정리"><a href="#7-정리" class="headerlink" title="7. 정리"></a>7. 정리</h3><ul><li>FHIR은 HL7의 최신 표준으로, v2·v3·CDA의 장점을 모으고 단점을 극복했다.</li><li>JSON/REST 기반으로 직관적이고 개발자 친화적이다.</li><li>이미 글로벌 빅테크와 각국 정부가 채택하고 있으며, 앞으로의 의료 데이터 교환 표준은 사실상 FHIR로 수렴 중이다.</li></ul><p>👉 요약하면, <strong>FHIR은 현재와 미래 의료 데이터 교환의 핵심 표준</strong>이다.</p>]]></content>
<categories>
<category> 🏥 HealthCare </category>
</categories>
<tags>
<tag> EHR </tag>
<tag> HL7 </tag>
<tag> HealthCare </tag>
<tag> FHIR </tag>
</tags>
</entry>
<entry>
<title>[HealthCare] HL7 CDA 표준 정리</title>
<link href="/2025/08/02/HealthCare/HL7/cda/"/>
<url>/2025/08/02/HealthCare/HL7/cda/</url>
<content type="html"><![CDATA[<h2 id="HL7-CDA-표준-정리"><a href="#HL7-CDA-표준-정리" class="headerlink" title="HL7 CDA 표준 정리"></a>HL7 CDA 표준 정리</h2><p>헬스데이터 스타트업이라면 반드시 알아야 할 표준 중 하나가 바로 <strong>CDA (Clinical Document Architecture)</strong> 이다.<br>이 글에서는 CDA가 어떤 배경에서 등장했는지, 문서 구조는 어떻게 생겼는지, 그리고 실제 어디에 활용되는지를 정리한다.</p><hr><h3 id="1-CDA란"><a href="#1-CDA란" class="headerlink" title="1. CDA란?"></a>1. CDA란?</h3><ul><li><strong>Clinical Document Architecture (임상 문서 구조)</strong></li><li>HL7 v3에서 파생된 표준으로, <strong>임상 정보를 문서 형태</strong>로 전자 교환하기 위해 설계되었다.</li><li>“메시지 기반 교환”이었던 v2/v3와 달리, CDA는 <strong>문서(document) 단위</strong>에 초점을 맞췄다.</li><li>현재도 여러 국가의 전자건강기록(EHR) 사업, 보험청구, 진료 요약서 교환 등에 사용된다.</li></ul><hr><h3 id="2-CDA의-구조"><a href="#2-CDA의-구조" class="headerlink" title="2. CDA의 구조"></a>2. CDA의 구조</h3><p>CDA 문서는 크게 <strong>헤더(Header)</strong> 와 <strong>본문(Body)</strong> 으로 나뉜다.</p><ul><li><p><strong>헤더(Header)</strong></p><ul><li>환자 식별자, 작성자(의사/간호사), 작성일, 문서 종류(예: Discharge Summary) 등 메타데이터</li><li>문서를 해석할 때 기본 틀을 제공</li></ul></li><li><p><strong>본문(Body)</strong></p><ul><li>실제 임상 내용</li><li>진단, 검사 결과, 처방, 경과, 퇴원 요약 등</li><li>구조적(Structured) 본문 또는 자유 서술(Text) 본문 모두 가능</li></ul></li></ul><blockquote><p>그런데 CDA는 HL7 v3에서 파생된 표준이므로, v3와의 차이를 이해하는 것이 중요하다.</p></blockquote><h4 id="HL7-v3와-CDA의-차이"><a href="#HL7-v3와-CDA의-차이" class="headerlink" title="HL7 v3와 CDA의 차이"></a>HL7 v3와 CDA의 차이</h4><table><thead><tr><th>구분</th><th>HL7 v3</th><th>CDA (Clinical Document Architecture)</th></tr></thead><tbody><tr><td><strong>출발점</strong></td><td>HL7이 v2 한계를 극복하려고 만든 <strong>차세대 메시징 표준</strong></td><td>HL7 v3의 기술을 바탕으로 만들어진 <strong>문서 교환 표준</strong></td></tr><tr><td><strong>표현 방식</strong></td><td>XML 기반, RIM(Reference Information Model) 전체를 따름</td><td>XML 기반, <code><ClinicalDocument></code> 루트 + 헤더/본문 구조</td></tr><tr><td><strong>단위</strong></td><td><strong>메시지 단위</strong> (Observation, Order, Patient 등 이벤트 중심)</td><td><strong>문서 단위</strong> (진료요약서, 퇴원 요약, 검사 리포트 등)</td></tr><tr><td><strong>구조</strong></td><td>매우 복잡, <code>classCode</code>·<code>moodCode</code> 등 속성 다수, 깊은 중첩</td><td>비교적 단순, 문서 헤더 + 본문으로 나뉨</td></tr><tr><td><strong>상호운용성</strong></td><td>국가·기관별 Implementation Guide 필요 → 글로벌 호환 실패</td><td>특정 문서 템플릿 정의 → 국가 단위 사업(EHR, 보험)에서 실제 활용</td></tr><tr><td><strong>현실 평가</strong></td><td>이론적으론 완벽, 하지만 <strong>너무 복잡해 실패</strong></td><td>단순 문서 교환에는 성공, 여전히 현역</td></tr><tr><td><strong>다음 세대</strong></td><td>CDA와 FHIR로 분화됨</td><td>이후 <strong>FHIR 문서 리소스(DocumentReference 등)</strong> 로 진화</td></tr></tbody></table><blockquote><p>📌 정리:<br>HL7 v3는 <strong>메시지 교환 전체를 새롭게 정의하려 한 대실험</strong>이었고,<br>CDA는 그 안에서 <strong>임상 문서를 교환하는 실용적 프로파일</strong>로 태어난 성공 사례다.<br>따라서 <strong>v3는 실패했지만 CDA는 지금도 보험청구·국가 EHR에서 현역으로 쓰인다.</strong></p></blockquote><hr><h3 id="3-CDA-XML-예시-축약본"><a href="#3-CDA-XML-예시-축약본" class="headerlink" title="3. CDA XML 예시 (축약본)"></a>3. CDA XML 예시 (축약본)</h3><pre class="language-markup" data-language="markup"><code class="language-markup"><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>ClinicalDocument</span> <span class="token attr-name">xmlns</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>urn:hl7-org:v3<span class="token punctuation">"</span></span><span class="token punctuation">></span></span> <span class="token comment"><!-- 문서 식별자 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>id</span> <span class="token attr-name">root</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>2.16.840.1.113883.19.5<span class="token punctuation">"</span></span> <span class="token attr-name">extension</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>TT998<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>typeId</span> <span class="token attr-name">root</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>2.16.840.1.113883.1.3<span class="token punctuation">"</span></span> <span class="token attr-name">extension</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>POCD_HD000040<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token comment"><!-- 환자 정보 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>recordTarget</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>patientRole</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>id</span> <span class="token attr-name">extension</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>12345<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>patient</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>name</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>given</span><span class="token punctuation">></span></span>Minjun<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>given</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"><</span>family</span><span class="token punctuation">></span></span>Kim<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>family</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>name</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>birthTime</span> <span class="token attr-name">value</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>19900101<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>administrativeGenderCode</span> <span class="token attr-name">code</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">"</span>M<span class="token punctuation">"</span></span><span class="token punctuation">/></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>patient</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>patientRole</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>recordTarget</span><span class="token punctuation">></span></span> <span class="token comment"><!-- 문서 본문 --></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>component</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>structuredBody</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>component</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>section</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>title</span><span class="token punctuation">></span></span>Discharge Summary<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>title</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"><</span>text</span><span class="token punctuation">></span></span>환자는 안정적인 상태로 퇴원하였다.<span class="token tag"><span class="token tag"><span class="token punctuation"></</span>text</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>section</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>component</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>structuredBody</span><span class="token punctuation">></span></span> <span class="token tag"><span class="token tag"><span class="token punctuation"></</span>component</span><span class="token punctuation">></span></span><span class="token tag"><span class="token tag"><span class="token punctuation"></</span>ClinicalDocument</span><span class="token punctuation">></span></span></code></pre><p>위 예시는 <strong>퇴원 요약서(Discharge Summary)</strong> 를 CDA 형식으로 기록한 단순 예시이다.<br>헤더에는 환자 이름과 성별, 생년월일이 들어가고, 본문에는 퇴원 소견이 서술돼 있다.</p><hr><h3 id="4-CDA의-특징과-장단점"><a href="#4-CDA의-특징과-장단점" class="headerlink" title="4. CDA의 특징과 장단점"></a>4. CDA의 특징과 장단점</h3><h4 id="장점"><a href="#장점" class="headerlink" title="장점"></a>장점</h4><ul><li><strong>문서 중심</strong>: 한 문서 안에 환자 맥락 + 임상 내용을 함께 담을 수 있다.</li><li><strong>표준화된 구조</strong>: 헤더/본문 구조가 명확하여 문서 간 교환이 용이하다.</li><li><strong>확장성</strong>: 자유 텍스트도 담을 수 있어 기존 문서 문화를 그대로 살릴 수 있다.</li><li><strong>호환성</strong>: 많은 국가 프로젝트(EHR, 보험)에서 채택되어 실제 현장 활용도가 높다.</li></ul><h4 id="단점"><a href="#단점" class="headerlink" title="단점"></a>단점</h4><ul><li><strong>여전히 XML 기반</strong>: 복잡하고 장황하다.</li><li><strong>구조적 제약</strong>: 본문에 자유 텍스트를 허용하면서도 구조적 요소를 강제해, 구현 난이도가 높다.</li><li><strong>실시간 교환 한계</strong>: CDA는 문서 단위라서, API처럼 세밀한 데이터 조회에는 적합하지 않다.</li></ul><hr><h3 id="5-실제-활용-사례"><a href="#5-실제-활용-사례" class="headerlink" title="5. 실제 활용 사례"></a>5. 실제 활용 사례</h3><ul><li><p><strong>국가 단위 EHR 사업</strong>:</p><ul><li>미국 Meaningful Use 프로그램에서 CDA 기반의 “Continuity of Care Document (CCD)” 활용</li><li>한국, 일본 등도 국가 표준 문서 교환에 CDA를 활용</li></ul></li><li><p><strong>보험 청구</strong>:</p><ul><li>진료 요약서, 처방전, 검사 리포트를 CDA 문서로 교환</li></ul></li><li><p><strong>병원 간 진료 정보 공유</strong>:</p><ul><li>환자가 다른 병원으로 전원될 때, CDA 퇴원 요약서로 정보를 전송</li></ul></li></ul><hr><h3 id="6-정리"><a href="#6-정리" class="headerlink" title="6. 정리"></a>6. 정리</h3><ul><li><strong>CDA</strong>는 HL7 v3에서 파생된 문서 교환 표준이다.</li><li>문서 단위로 환자 정보와 임상 데이터를 전달할 수 있어, 보험/진료요약/국가사업에서 여전히 많이 쓰인다.</li><li>그러나 XML 기반 특유의 장황함과 실시간 교환 한계 때문에, 최신 세대인 <strong>FHIR</strong>이 부상하게 되었다.</li></ul><p>👉 요약하면, <strong>CDA는 v3의 유산이지만 여전히 현역에서 쓰이는 표준</strong>이며, FHIR로 이어지는 진화의 징검다리다.</p>]]></content>
<categories>
<category> 🏥 HealthCare </category>
</categories>
<tags>
<tag> EHR </tag>
<tag> HL7 </tag>
<tag> HealthCare </tag>
<tag> CDA </tag>
</tags>
</entry>
<entry>
<title>직접 개발한 사이트, 애드센스 등록 성공!</title>
<link href="/2025/07/10/Etc/Build-Site-Adsense/"/>
<url>/2025/07/10/Etc/Build-Site-Adsense/</url>
<content type="html"><![CDATA[<p>예전부터 직접 만든 사이트에 애드센스를 달아보고 싶었는데, 이번에 애드센스를 무사히 통과했다!</p><p>이번 포스팅에서는 어떤 방식으로 만들었고, 심사를 위해 어떤 부분을 신경 썼는지, 그리고 실제 심사 전략까지 기록해본다.<br>검색해보니까 대부분 github page template이나 tistory써서 이런 글은 많이 없더라.. 글 많이 써주세요 동료님들 🥹</p><hr><h2 id="도메인-전략-루트도메인-vs-서브도메인"><a href="#도메인-전략-루트도메인-vs-서브도메인" class="headerlink" title="도메인 전략: 루트도메인 vs 서브도메인"></a>도메인 전략: 루트도메인 vs 서브도메인</h2><p>2024년까지는 애드센스가 <strong>서브도메인도 개별 등록 대상</strong>이었다.<br>하지만 규정이 바뀌면서 2025년부터는 <strong>루트 도메인만 등록하면 서브도메인 전체에 적용 가능</strong>하다는 식으로 변경되었다.</p><p>나는 <a href="https://anb-network.com/"><code>anb-network.com</code></a>이라는 도메인을 <strong>개인사업자 홍보용 사이트</strong>로 사용할 예정이었기 때문에, 애드센스 심사 페이지로 쓰기에는 다소 <strong>상업적 냄새가 강할 것</strong>이라 판단했다.</p><p>그래서 혹시 모를 사태를 대비해 서브도메인으로 따로 제작한 <a href="https://mentoring-career.anb-network.com/"><code>mentoring-career.anb-network.com</code></a> 사이트를 <strong>잠시 루트 도메인에 업로드</strong>해 심사를 진행했고, 애드센스가 통과되자 다시 서브도메인으로 돌려놓았다.<br>이 방식은 <strong>심사 과정에서 상업성 판단을 회피하는 전략</strong>으로 꽤 유효했던 것 같다.</p><hr><h2 id="프론트엔드-구조-SSR-서버사이드-렌더링-선택-이유"><a href="#프론트엔드-구조-SSR-서버사이드-렌더링-선택-이유" class="headerlink" title="프론트엔드 구조: SSR (서버사이드 렌더링) 선택 이유"></a>프론트엔드 구조: SSR (서버사이드 렌더링) 선택 이유</h2><p>Next.js를 사용했고, 기본 설정은 <code>app router</code> 기반 SSR이었다.<br>정적 페이지보다 <strong>서버 사이드 렌더링이 콘텐츠 신뢰도와 구조화된 데이터 면에서 유리하다는 글</strong>을 많이 참고했고, 실제로 <code>metadata</code> 구조가 깔끔하게 반영되는 것도 SSR의 장점 중 하나였다.</p><p>실제로 <code><head></code> 내부에 다음과 같은 메타데이터를 포함시켰다:</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">export</span> <span class="token keyword">const</span> metadata <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">title</span><span class="token operator">:</span> <span class="token string">"알아보기 | 원격영상 진로멘토링"</span><span class="token punctuation">,</span> <span class="token literal-property property">description</span><span class="token operator">:</span> <span class="token string">"클라우드 엔지니어가 하는 일, 필요한 기술, 진로 정보, 하루 일과 등을 친절하게 소개한 사전 수업용 진로 가이드입니다."</span><span class="token punctuation">,</span> <span class="token literal-property property">keywords</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token string">"클라우드 엔지니어"</span><span class="token punctuation">,</span> <span class="token string">"진로 정보"</span><span class="token punctuation">,</span> <span class="token string">"IT 진로"</span><span class="token punctuation">,</span> <span class="token string">"클라우드 기술"</span><span class="token punctuation">,</span> <span class="token string">"DevOps"</span><span class="token punctuation">,</span> <span class="token string">"SRE"</span><span class="token punctuation">,</span> <span class="token string">"플랫폼 엔지니어"</span><span class="token punctuation">,</span> <span class="token string">"하루 일과"</span><span class="token punctuation">,</span> <span class="token string">"진로체험"</span><span class="token punctuation">,</span> <span class="token string">"사전 학습"</span><span class="token punctuation">,</span> <span class="token string">"AI 시대 클라우드"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token literal-property property">alternates</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">canonical</span><span class="token operator">:</span> <span class="token string">"https://mentoring-career.anb-network.com/info"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">robots</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">index</span><span class="token operator">:</span> <span class="token boolean">true</span><span class="token punctuation">,</span> <span class="token literal-property property">follow</span><span class="token operator">:</span> <span class="token boolean">true</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token literal-property property">openGraph</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token literal-property property">type</span><span class="token operator">:</span> <span class="token string">"article"</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p>심사에 큰 영향을 준 것은 단순히 키워드가 아니라, <strong>페이지마다 고유의 타이틀과 설명, <code>index/follow</code> 로봇 태그를 명시</strong>했다는 점이다.</p><hr><h2 id="사이트-구조-및-페이지-수-고려"><a href="#사이트-구조-및-페이지-수-고려" class="headerlink" title="사이트 구조 및 페이지 수 고려"></a>사이트 구조 및 페이지 수 고려</h2><p>애드센스는 심사 과정에서 <strong>“신뢰할 수 있는 사이트”</strong> 인지를 상당히 엄격하게 본다.<br>그 기준 중 하나가 <strong>페이지 수</strong>와 <strong>기초 페이지의 존재 여부</strong>다.</p><p>나는 다음 <strong>3개의 필수 페이지</strong>를 구성했다:</p><ul><li><code>/about</code> – 사이트 운영 목적과 배경 설명</li><li><code>/privacy</code> – 개인정보 처리방침</li><li><code>/terms</code> – 이용 약관</li><li><code>/contact</code> – 이메일 기반 문의처는 페이지 없이 mailto로 간단하게 구성했다.</li></ul><p>그 외에 <strong>메인 콘텐츠 페이지는 최소 3개 이상</strong>으로 구성했다:</p><ul><li><code>/info</code> – 직업 소개 / 진로 가이드</li><li><code>/deploy</code> – 클라우드 배포 실습</li><li><code>/game</code> – 클라우드 엔지니어 시뮬레이션 게임. 직접 js로 간단한 카드게임을 구현했다.</li></ul><p>실제로 <strong>콘텐츠 페이지가 1~2개뿐이면 거절 사례</strong>가 많다는 글을 많이 봤기에,<br>최소 3개 이상의 콘텐츠를 확보하려 노력했다.</p><hr><h2 id="기타-체크한-항목들"><a href="#기타-체크한-항목들" class="headerlink" title="기타 체크한 항목들"></a>기타 체크한 항목들</h2><ul><li><code>sitemap.xml</code> 직접 생성하여 Google Search Console에 제출</li><li><code>robots.txt</code> 작성</li><li>RSS는 제출하지 않음: 직업 체험 사이트 특성상 자주 업데이트되지 않기 때문</li><li>모든 페이지의 헤더, 푸터 일관성 유지</li><li>모바일 대응 + 기본적인 반응형 처리 완료: 일일이 만들기 귀찮아서 tailwind로 처리</li><li>광고단위 생성 및 활용: 광고 노출 시 원하는 형태의 광고를 송출할 수 있도록 세팅</li></ul><p>이 모든 항목들을 고려해서 그런지, 심사를 요청한지 약 18시간 만에 바로 <strong>합격</strong>을 받을 수 있었다!</p><hr><h2 id="통과-이후-전략"><a href="#통과-이후-전략" class="headerlink" title="통과 이후 전략"></a>통과 이후 전략</h2><p>애드센스가 통과된 이후, 루트 도메인(<a href="https://anb-network.com/"><code>anb-network.com</code></a>)은 원래 목적대로 <strong>개인사업자 홍보용</strong>으로 구성했다.<br>심사를 위해 잠시 루트 도메인에 걸었던 직업 체험 사이트는<br><strong>서브도메인(<a href="https://mentoring-career.anb-network.com/"><code>mentoring-career.anb-network.com</code></a>)으로 다시 돌려서 운영 중이다.</strong></p><p>애드센스 코드 자체는 <strong>서브도메인에 삽입해도 정상 노출</strong>된다.<br>동일하게 ads.txt를 생성하고, 루트도메인의 ads.txt내용을 그대로 복붙하면 된다.</p><hr><h2 id="마무리"><a href="#마무리" class="headerlink" title="마무리"></a>마무리</h2><p>나도 이전에는 맨날 오픈소스 템플릿만 가지고, 혹은 티스토리로 애드센스를 도전했는데,<br>이번에 애드센스 승인 사이트를 직접 만들면서 특히 SEO관점에서 많은 성장을 한 것 같다.</p><p>혹여나 직접 만든 사이트에 애드센스를 달 예정이신 분들이 계시다면 도움이 되길 바란다 🍀</p>]]></content>
<categories>
<category> 💾 Etc </category>
</categories>
<tags>
<tag> Adsense </tag>
<tag> NextJS </tag>
</tags>
</entry>
<entry>
<title>[GCP] GCP Professional Cloud Architect(PCA) 자격증 시험 준비 및 합격 후기</title>
<link href="/2025/06/10/Certificate/GCP/GoogleCloudPCA/"/>
<url>/2025/06/10/Certificate/GCP/GoogleCloudPCA/</url>
<content type="html"><![CDATA[<h2 id="GCP-사전-지식"><a href="#GCP-사전-지식" class="headerlink" title="GCP 사전 지식"></a>GCP 사전 지식</h2><ul><li>없음. 대충 들은건 있어가지고 어떤 서비스가 있는지는 아는데, 회사에서 AWS만 주구장창 쓰고 있으며, 회사가 너무 좋은 바람에 이직을 못하고 있어 다른 클라우드는 솔직히 써본 적이 없음.</li><li>즉, 전반적인 클라우드 지식은 알고있다만 <strong>Google Cloud 아키텍쳐</strong>에는 전혀 익숙하지 않았던 상태였으며 기초부터 공부를 시작함</li></ul><h2 id="시험-준비-기간-1달-인데-빡집중한거는-2주-정도"><a href="#시험-준비-기간-1달-인데-빡집중한거는-2주-정도" class="headerlink" title="시험 준비 기간: 1달 (인데 빡집중한거는 2주 정도)"></a>시험 준비 기간: 1달 (인데 빡집중한거는 2주 정도)</h2><h3 id="1-전반적인-개념-정리-하루"><a href="#1-전반적인-개념-정리-하루" class="headerlink" title="(1) 전반적인 개념 정리: 하루"></a>(1) 전반적인 개념 정리: 하루</h3><ul><li>Google Cloud Architecture Framework를 중심으로 문서 정독</li><li>IAM, VPC 피어링, Interconnect, Load Balancer 타입 구분 등 기본 정리</li><li>총 2-3페이지 정도로 압축 요약을 진행. 꽤 요약을 잘했는지 여기에서 시험문제가 다 나와서 편하게 응시한 것 같다.</li></ul><h3 id="2-시험-문제-공부-덤프-무료"><a href="#2-시험-문제-공부-덤프-무료" class="headerlink" title="(2) 시험 문제 공부: 덤프 (무료)"></a>(2) 시험 문제 공부: 덤프 (무료)</h3><ul><li>덤프: 일부 문제의 답에 대해서 갑론을박이 있으며, 이는 chatGPT를 활용해서 맞춰보는 것을 추천함<ul><li><a href="https://www.examtopics.com/exams/google/professional-cloud-architect/view/">Examtopics</a><ul><li>AWS 시험볼 때도 사용했던 사이트</li><li>구글 캐시를 이용하면 이후 문제도 무료로 풀 수 있었으나, <strong>2025년 5월 기준으로 막힌 것으로 확인됨</strong>. 무료 문제를 풀거라면 차라리 아래 사이트를 이용하는 것을 추천함</li></ul></li><li><a href="https://www.examprepper.co/exam/4/1">ExamPrepper</a><ul><li>Examtopics와 비슷한 무료 덤프 사이트. 여기서 실제 시험 문제를 많이 볼 수 있었음</li></ul></li><li>Case Study에서는 가장 최적의 효율을 낼 수 있는 답안을 선택<ul><li>PCA에서는 Mountkirk Games, TerramEarth만 나온다. 나머지는 공부 안해도 된다.</li></ul></li></ul></li><li>[참고] 유료 문제는 Udemy에서 많이 구매해 푸는 것 같다. 필자는 ExamPrepper만 풀어봐서 모르겠다. 개인적으로 ExamPrepper를 추천하는 것이, 필자는 이 사이트를 시험보기 3시간 전에 알게되어 급하게 풀어본거였는데, 문제가 여기서 15개나 나왔다.</li></ul><h2 id="시험-정보-팁"><a href="#시험-정보-팁" class="headerlink" title="시험 정보 & 팁"></a>시험 정보 & 팁</h2><ul><li>시험 언어: 영어 (한국어 미지원)</li><li>시험 방식: 온라인 / 오프라인<ul><li>아래 적어놓겠지만, 보안이 매우 빡세기 때문에 세팅이 귀찮다면 오프라인으로 보는 것을 추천한다.</li></ul></li><li>문제 수: 50문제<ul><li>필자의 경우, 1번부터 10번까지 Case Study 문제가</li><li>이후로는 기본적인 GCP 및 클라우드 관련 문제가 출제됨</li></ul></li><li>시험 시간: 2시간</li><li>합격 점수 기준: 80% 이상</li></ul><p>구글 자격증은 클라우드 업계에서도 어렵다고 소문이 자자한 자격증이다. 그리고 인터넷에 검색해보면 생각보다 한국어 후기가 그렇게 많지 않다.</p><p>공부를 시작한 당시 왜 그런가 싶었는데, 알고보니 일단 언어의 벽이 가장 큰 문제였다. 시대가 어느땐데 아직도 한국어 지원이 안됨 ㅎㅎㅎㅎ 이게 바로 대기업?!</p><h2 id="시험-신청-온라인-및-준비물"><a href="#시험-신청-온라인-및-준비물" class="headerlink" title="시험 신청 (온라인) 및 준비물"></a>시험 신청 (온라인) 및 준비물</h2><ul><li>시험 신청: <a href="https://www.webassessor.com/googlecloud">https://www.webassessor.com/googlecloud</a> -> Access Webassessor -> 원하는 형태의 시험을 선택할 것<ul><li>webassessor에 접속 후, My Assessments로 이동 후<ul><li>Profile에 들어가서 Legal First Name, Legal Last Name 스펠링을 확인할 것</li><li>Biometric Profile도 확인할 것<ul><li>될 수 있으면 낮에 사진을 찍는 것을 추천한다. 필자는 늦게 알아서 밤에 사진을 찍었는데, 빛에 되게 민감하다. 스탠드 불 한칸 가지고 너무 밝고 어둡다고 하더라;</li></ul></li><li>(온라인 시험 한정) Install New Secure Browser 클릭하여 Secure Browser 프로그램을 설치할 것</li></ul></li></ul></li><li>마이크, 웹캠 관련 시스템 설정: <a href="https://www.kryteriononline.com/systemcheck">https://www.kryteriononline.com/systemcheck</a></li><li>기타 준비물: ID카드 (여권)<ul><li>온라인 시험을 보면, 보안 검색이 끝난 후 화장실 및 물을 가져올 수 있는 시간을 준다. 필자는 새벽에 시험을 보는 상황이었던지라 바로 시험으로 간다고 해서 시험을 봤다.</li></ul></li></ul><h2 id="시험-팁"><a href="#시험-팁" class="headerlink" title="시험 팁"></a>시험 팁</h2><ul><li>PC에서 Case Study는 무조건 Mountkirk Games, TerramEarth에서만 나오는 것 같다. 인터넷에 여러 번 검색을 해봤는데, 모두가 하나같이 이 둘 말고는 전혀 나오지 않았다고 한다.<ul><li>개인적으로 Case Study가 가장 어려웠던 것 같다. 다른 것들은 딱봐도 정답이고 아니고를 판별할 수 있었는데, 이거는 선택지가 전부 말이 되기 때문이었다.</li><li>필자는 문제에서 특별한 요구사항이 없는 한, “비용효율적”인 방향으로 정답을 골랐다. 이것도 문제를 많이 풀면 적중률은 올라갈 수 있겠으나… 모르겠다. 너무 어려웡</li></ul></li><li>나같이 평범한 한국인이라면, 대부분 시험을 영어로 볼 것이다. 우리가 외국인이라고 추가시간을 주지 않는다. 이 쯤되면 AWS가 그리워진다…</li><li>AWS와 마찬가지로 GCP에서도 온라인 스터디 여는데, 참여 시 50% 시험응시 할인 쿠폰을 받을 수 있다. 원래 회사에서 시험비도 지원해줘서 굳이 들어갈 필요는 없었으나 공식스터디라고 하니까 혹여나 해서 2025년 상반기에 참여했는데, 스터디가 생각보다 도움이 안되어서 중도하차를 했다. 시험비를 아낄 목적이라면 적당히 들어가서 최소조건만 만족하고 바우처를 받으면 좋을 것 같다.</li></ul><h2 id="시험-후기"><a href="#시험-후기" class="headerlink" title="시험 후기"></a>시험 후기</h2><ul><li>총 50문제 나왔고 검토는 1번해서 1시간만에 끝냈다. AWS에서도 언급했듯이, 내가 잘한다는 의미는 아니고 찍거나 헷갈리는 문제는 전부 틀리는 사람인지라 굳이 시간낭비를 하기 싫었다 ㅎㅎ;; 무엇보다 이때 새벽 3시 30분에 시험봐서 그냥 자고싶었음ㅠㅠ</li><li>보안 개빡세다. 여기도 공항 몸수색 뺨치는 수준으로 본다. 책상만 하더라도 왼쪽, 오른쪽, 앞, 뒤, 모서리 사방을 전부 찍으라고 하더라. 심지어 노트북을 주변 한바퀴 천천히 돌려서 카메라에 잘 담기게 해달라고 요청도 한다. 한번 적당히 돌려줬는데 너무 빠르다고 다시해달라 하더라..</li><li>합불여부는 시험 끝내면 바로 볼 수 있다. 단 점수는 안나온다.</li><li>시험 난이도는.. Case Study가 긴가민가 했으나 그 외로는덤프에 나왔던거 그대로 나온게 많아서 괜찮았다.</li><li>시험에 통과하면 다음 GCP 자격증 시험 50%를 할인 바우처를 받을 수 있다.</li><li>일부 블로그 글에는 시험 합격 시 GCP굿즈를 받을 수 있다고 하는데, 올해 3월부터 해당 혜택이 사라졌다고 한다. 요즘 사정이 안좋다고 들었는데 생각보다 많이 안좋은가보다..ㅠㅠ</li></ul><img src="/2025/06/10/Certificate/GCP/GoogleCloudPCA/gcp_pca.avif" class="" title="GCP Professional Cloud Architect 자격증">]]></content>
<categories>
<category> 📝 Certificate </category>
</categories>
<tags>
<tag> GCP </tag>
<tag> Cloud </tag>
</tags>
</entry>
<entry>
<title>[HealthCare] HL7 v3의 실패 이유 정리</title>
<link href="/2025/03/05/HealthCare/HL7/v3/"/>
<url>/2025/03/05/HealthCare/HL7/v3/</url>
<content type="html"><![CDATA[<h2 id="HL7-v3의-실패-이유-정리"><a href="#HL7-v3의-실패-이유-정리" class="headerlink" title="HL7 v3의 실패 이유 정리"></a>HL7 v3의 실패 이유 정리</h2><p>헬스데이터 스타트업이라면 HL7 v2 말고도 <strong>v3의 역사와 실패 이유</strong>를 반드시 알아야 한다.<br>이 글에서는 HL7 v3가 어떤 배경에서 등장했고, 왜 실패했는지, 그리고 이후 표준에 어떤 영향을 미쳤는지 정리한다.</p><hr><h3 id="1-HL7-v3란"><a href="#1-HL7-v3란" class="headerlink" title="1. HL7 v3란?"></a>1. HL7 v3란?</h3><ul><li>2000년대 초반 HL7이 새롭게 만든 표준이다.</li><li><strong>XML 기반</strong>으로 더 엄격하고 체계적인 데이터 구조를 제공한다.</li><li>메시지를 <strong>Reference Information Model (RIM)</strong> 이라는 추상 데이터 모델에 맞춰 표현한다.</li><li>목표: v2의 자유로운(때로는 제각각인) 메시지 구조 문제를 해결하고, 전 세계적으로 일관된 모델을 제시하는 것.</li></ul><hr><h3 id="2-HL7-v3의-특징과-장단점"><a href="#2-HL7-v3의-특징과-장단점" class="headerlink" title="2. HL7 v3의 특징과 장단점"></a>2. HL7 v3의 특징과 장단점</h3><h4 id="장점"><a href="#장점" class="headerlink" title="장점"></a>장점</h4><ul><li><strong>구조적 일관성</strong>: 모든 메시지가 RIM이라는 공통 모델을 기반으로 작성된다.</li><li><strong>표준 코드 체계 사용</strong>: LOINC, SNOMED CT 같은 코드 시스템을 활용하여 의미를 명확히 표현할 수 있다.</li><li><strong>기계 판독성</strong>: XML 기반이므로 파싱과 검증이 용이하다.</li></ul><h4 id="단점"><a href="#단점" class="headerlink" title="단점"></a>단점</h4><ul><li><strong>과도한 복잡성</strong>:<ul><li>메시지 안에 <code>classCode</code>, <code>moodCode</code>, <code>codeSystem</code>, <code>interpretationCode</code> 등 필수 속성이 너무 많다.</li><li>개발자는 값 하나를 표현하기 위해 수많은 태그와 속성을 채워야 한다.</li></ul></li><li><strong>깊은 중첩 구조</strong>:<ul><li>Observation 안에 component/observation이 계속 중첩된다.</li><li>사람이 읽고 쓰기에 가독성이 떨어지고, 시스템 구현도 어렵다.</li></ul></li><li><strong>nullFlavor 문제</strong>:<ul><li>값이 없을 때도 단순히 비워둘 수 없고 <code>nullFlavor="UNK"</code> 같은 코드로 반드시 표현해야 한다.</li><li>각 기관이 이를 다르게 해석하면서 상호운용성이 깨졌다.</li></ul></li><li><strong>국가별 Implementation Guide(IG) 의존</strong>:<ul><li>HL7 v3 자체만으로는 너무 추상적이어서, 실제 사용을 위해서는 각 나라/기관이 IG를 별도로 만들어야 했다.</li><li>결과적으로 “국제 표준”인데도 불구하고, 국경을 넘으면 호환성이 보장되지 않았다.</li></ul></li></ul><hr><h3 id="3-결과-왜-실패했는가"><a href="#3-결과-왜-실패했는가" class="headerlink" title="3. 결과: 왜 실패했는가?"></a>3. 결과: 왜 실패했는가?</h3><ul><li><p><strong>현실적 구현 난이도 ↑</strong><br>→ 복잡한 XML 구조와 필드 정의 때문에 실제 시스템에 적용하기 어려웠다.</p></li><li><p><strong>기관별 해석 차이 ↑</strong><br>→ 같은 모델을 두고도 IG마다 다르게 구현, 결국 “표준이지만 표준이 아닌” 상황이 되었다.</p></li><li><p><strong>개발자/벤더 채택 저조</strong><br>→ v2 메시지는 단순해서 인터페이스 개발자가 빠르게 붙일 수 있었지만, v3는 학습곡선이 너무 높았다.</p></li><li><p><strong>상호운용성 확보 실패</strong><br>→ 원래 목표는 글로벌 상호운용성 확대였으나, 오히려 v2보다도 통합이 어려워졌다.</p></li></ul><p>➡️ 결국 HL7 v3는 <strong>국제적으로 널리 쓰이지 못하고 사실상 실패한 표준</strong>이 되었다.</p><hr><h3 id="4-이후로-이어진-흐름"><a href="#4-이후로-이어진-흐름" class="headerlink" title="4. 이후로 이어진 흐름"></a>4. 이후로 이어진 흐름</h3><ul><li><p><strong>CDA (Clinical Document Architecture)</strong></p><ul><li>v3의 일부 기술을 가져와 문서 중심 교환 표준으로 자리 잡았다.</li><li>환자 퇴원요약서, 진료 기록, 검사 리포트 등 <strong>문서 단위</strong> 교환에 성공적으로 적용.</li><li>지금도 국가 단위 EHR 프로젝트나 보험청구에서 쓰인다.</li></ul></li><li><p><strong>FHIR (Fast Healthcare Interoperability Resources)</strong></p><ul><li>v3의 복잡성을 교훈 삼아 2010년대에 등장.</li><li>JSON/XML 기반 + REST API 친화적.</li><li>구조가 단순하고 직관적이라 빠르게 전 세계에서 채택 중.</li></ul></li></ul><hr><h3 id="5-정리"><a href="#5-정리" class="headerlink" title="5. 정리"></a>5. 정리</h3><ul><li><p>HL7 v3는 <strong>이론적으로는 완벽</strong>했으나,</p><ul><li>너무 복잡한 XML 구조,</li><li>nullFlavor 등 과도한 제약,</li><li>국가별 IG에 의존한 해석 차이<br>때문에 <strong>실제 현장에서는 실패</strong>했다.</li></ul></li><li><p>그러나 v3의 시도는 헛되지 않았다.</p><ul><li>CDA라는 문서 교환 표준이 성공적으로 자리잡았고,</li><li>이후 FHIR이 “현실적이고 개발자 친화적인 표준”으로 발전할 수 있는 기반이 되었다.</li></ul></li></ul><p>👉 요약하면, <strong>v3는 실패했지만 CDA와 FHIR로 이어진 진화 과정에서 중요한 디딤돌이었다.</strong></p>]]></content>
<categories>
<category> 🏥 HealthCare </category>
</categories>
<tags>
<tag> EHR </tag>
<tag> HL7 </tag>
<tag> HealthCare </tag>
<tag> CDA </tag>
</tags>
</entry>
<entry>
<title>[Java] JDK 버전, javac와 java 차이, 그리고 IDE 빌드 시스템 정리</title>
<link href="/2025/02/28/Language/Java-faq/"/>
<url>/2025/02/28/Language/Java-faq/</url>
<content type="html"><![CDATA[<p>스프링(Spring)이나 자바(Java)를 공부하다 보면 가장 먼저 부딪히는 부분이 있다.<br>바로 <strong>JDK 버전 차이</strong>, <strong>javac/java 명령어</strong>, 그리고 <strong>Gradle, Maven 같은 빌드 시스템</strong>이다.<br>처음 접할 때는 개념이 섞여서 헷갈리기 쉬운데, 한 번에 큰 그림을 잡아두면 이후 학습이 훨씬 수월해진다.</p><p>이번 글에서는 실제로 많이 묻는 질문들을 묶어서 정리해본다.</p><p><br><br></p><h2 id="Java-8과-Java-21의-차이"><a href="#Java-8과-Java-21의-차이" class="headerlink" title="Java 8과 Java 21의 차이"></a>Java 8과 Java 21의 차이</h2><hr><p>많은 강의가 여전히 <strong>Java 8</strong>을 기준으로 설명한다.<br>하지만 요즘 개발 환경에서는 <strong>Java 17</strong>이나 <strong>Java 21</strong> 같은 최신 LTS(Long Term Support) 버전을 더 자주 사용한다.</p><ul><li><p><strong>Java 8 (2014 출시)</strong></p><ul><li>람다(Lambda), 스트림(Stream), Optional, 새로운 날짜/시간 API가 도입되었다.</li><li>이 시점을 기점으로 현대적인 자바 문법이 자리 잡았다.</li></ul></li><li><p><strong>Java 21 (2023 출시, 최신 LTS)</strong></p><ul><li>record 클래스, sealed 클래스, switch 표현식, 패턴 매칭 같은 새로운 문법을 제공한다.</li><li>Virtual Thread(Project Loom) 지원으로 동시성 프로그래밍 성능이 크게 개선되었다.</li><li>GC(가비지 컬렉터)도 발전하여 대규모 애플리케이션에서 더 효율적이다.</li></ul></li></ul><p>정리하면, <strong>Java 21은 Java 8의 모든 기능을 포함하고 추가 기능이 더 많다</strong>.<br>따라서 학습을 목적으로 한다면 최신 버전을 그대로 사용해도 문제가 없다.<br>다만 강의 예제 코드가 Java 8 기준이라면 화면이나 설치 과정에서 차이가 있을 수 있으니 주의할 필요가 있다.</p><p><br><br></p><h2 id="javac와-java-명령어-차이"><a href="#javac와-java-명령어-차이" class="headerlink" title="javac와 java 명령어 차이"></a>javac와 java 명령어 차이</h2><hr><p>자바 개발을 처음 배우면 <code>javac</code>와 <code>java</code> 명령어의 차이가 헷갈리곤 한다.</p><ul><li><p><strong>javac</strong></p><ul><li>Java Compiler의 줄임말이다.</li><li><code>.java</code> 소스 파일을 컴파일해서 <code>.class</code> 바이트코드 파일을 생성한다.</li><li>예: <code>javac Hello.java</code> → <code>Hello.class</code> 생성</li></ul></li><li><p><strong>java</strong></p><ul><li>JVM(Java Virtual Machine)을 실행하는 명령어이다.</li><li><code>.class</code> 파일을 읽어 실제 실행한다.</li><li>예: <code>java Hello</code> → <code>Hello.class</code> 실행</li></ul></li></ul><p>흐름을 정리하면, <code>javac</code>는 <strong>번역기</strong>, <code>java</code>는 <strong>낭독기</strong>라고 비유할 수 있다.<br>즉, 1) <code>javac</code>로 소스를 바이트코드로 변환하고, 2) <code>java</code>로 JVM에서 실행하는 구조이다.</p><p><br><br></p><h2 id="IDE-IntelliJ-에서-실행-버튼을-누르면"><a href="#IDE-IntelliJ-에서-실행-버튼을-누르면" class="headerlink" title="IDE(IntelliJ)에서 실행 버튼을 누르면?"></a>IDE(IntelliJ)에서 실행 버튼을 누르면?</h2><hr><p>많은 자바 개발자가 JetBrains의 <strong>IntelliJ IDEA</strong>를 사용한다.<br>여기서 실행 버튼(▶️)을 누르면 내부적으로는 <code>javac</code>와 <code>java</code>가 자동으로 실행된다.<br>하지만 단순히 명령어만 실행하는 것이 아니라, IDE는 프로젝트 설정에 따라 <strong>클래스패스(classpath)</strong>, <strong>라이브러리(JAR)</strong>, <strong>빌드 툴(Gradle/Maven)</strong> 설정까지 함께 관리한다.</p><p>즉, 개발자가 매번 명령어를 수동으로 입력하지 않아도 IDE가 대신 처리해주는 셈이다.<br>이 덕분에 코드 작성 → 빌드 → 실행 → 디버깅까지 한 번에 진행할 수 있다.</p><p><br><br></p><h2 id="빌드-시스템-Gradle-vs-Maven-vs-IntelliJ-Build"><a href="#빌드-시스템-Gradle-vs-Maven-vs-IntelliJ-Build" class="headerlink" title="빌드 시스템: Gradle vs Maven vs IntelliJ Build"></a>빌드 시스템: Gradle vs Maven vs IntelliJ Build</h2><hr><p>스프링 프로젝트를 진행하다 보면 빌드 시스템 선택이 필수적이다.</p><ul><li><strong>Gradle</strong><ul><li>Groovy 또는 Kotlin DSL 기반의 빌드 스크립트를 사용한다.</li><li>캐시와 병렬 빌드가 지원되어 속도가 빠르다.</li><li>최신 스프링 부트 프로젝트에서 기본적으로 권장된다.</li></ul></li></ul><blockquote><p><strong>Gradle DSL: Groovy vs Kotlin</strong></p><p>Gradle을 사용할 때는 <strong>빌드 스크립트를 어떤 언어로 작성할지</strong> 정해야 한다.<br>기본적으로 두 가지 DSL(Domain Specific Language)을 지원한다.</p><ul><li><p><strong>Groovy DSL (<code>build.gradle</code>)</strong></p><ul><li>전통적인 방식, 예제와 자료가 많다.</li><li>동적 타입 기반이라 문법이 유연하지만, 자동완성이나 에러 검출은 다소 약하다.</li></ul></li><li><p><strong>Kotlin DSL (<code>build.gradle.kts</code>)</strong></p><ul><li>정적 타입 기반이라 IDE 자동완성이 강력하다.</li><li>최근 Gradle과 스프링 공식 문서에서 적극적으로 권장되는 방식이다.</li><li>러닝 커브가 있지만, 유지보수성과 타입 안정성이 뛰어나다.<br>정리하면, <strong>새로운 스프링 부트 프로젝트</strong>를 시작한다면 <strong>Kotlin DSL</strong>을 추천한다.<br>다만, 강의나 기업 프로젝트에서 <strong>Groovy DSL</strong>을 사용한다면 그대로 따라가는 것도 문제없다. 빌드 결과는 동일하기 때문이다.</li></ul></li></ul></blockquote><p><br><br></p><ul><li><p><strong>Maven</strong></p><ul><li>XML 기반 빌드 설정을 사용한다.</li><li>표준화된 구조 덕분에 배우기 쉽고 예제와 문서가 많다.</li><li>보수적인 기업 프로젝트에서 여전히 널리 쓰인다.</li></ul></li><li><p><strong>IntelliJ Build</strong></p><ul><li>IDE 내부 전용 빌드 기능이다.</li><li>로컬에서 빠른 테스트에는 적합하지만, CI/CD 파이프라인이나 배포 환경에서는 한계가 있다.</li></ul></li></ul><p>정리하면, 개인 프로젝트나 최신 환경에서는 <strong>Gradle</strong>,<br>기업이나 강의에서 정해둔 환경이 있다면 <strong>Maven</strong>,<br>그리고 IDE 빌드는 <strong>보조 수단</strong> 정도로 쓰는 것이 가장 합리적이다.</p><p><br><br></p><h2 id="Java-21과-Virtual-Thread"><a href="#Java-21과-Virtual-Thread" class="headerlink" title="Java 21과 Virtual Thread"></a>Java 21과 Virtual Thread</h2><hr><p>스레드(Thread)는 자바 학습에서 중요한 주제다.<br>기존에는 플랫폼 스레드(운영체제 스레드) 기반으로 동작했지만, <strong>Java 21</strong>에서는 <strong>Virtual Thread(Project Loom)</strong> 가 정식 도입되었다.</p><ul><li><p><strong>플랫폼 스레드</strong></p><ul><li>운영체제 스레드와 1:1 매핑된다.</li><li>무겁고, 동시에 수천 개 이상 띄우기에는 한계가 있다.</li></ul></li><li><p><strong>가상 스레드 (Virtual Thread)</strong></p><ul><li>JVM이 관리하는 경량 스레드이다.</li><li>수십만 개를 띄워도 부담이 적어 <strong>블로킹 I/O 처리</strong>에 특히 유리하다.</li><li>코드 작성 방식은 기존 스레드와 거의 같지만, 성능상 이점이 크다.</li></ul></li></ul><p>예시 (Java 21):</p><pre class="language-java" data-language="java"><code class="language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">VtDemo</span> <span class="token punctuation">{</span> <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span> <span class="token keyword">try</span> <span class="token punctuation">(</span><span class="token keyword">var</span> exec <span class="token operator">=</span> <span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>concurrent<span class="token punctuation">.</span></span>Executors</span><span class="token punctuation">.</span><span class="token function">newVirtualThreadPerTaskExecutor</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">var</span> futures <span class="token operator">=</span> <span class="token class-name"><span class="token namespace">java<span class="token punctuation">.</span>util<span class="token punctuation">.</span>stream<span class="token punctuation">.</span></span>IntStream</span><span class="token punctuation">.</span><span class="token function">range</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">,</span> <span class="token number">10_000</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">mapToObj</span><span class="token punctuation">(</span>i <span class="token operator">-></span> exec<span class="token punctuation">.</span><span class="token function">submit</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-></span> <span class="token punctuation">{</span> <span class="token class-name">Thread</span><span class="token punctuation">.</span><span class="token function">sleep</span><span class="token punctuation">(</span><span class="token number">50</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 블로킹 I/O 흉내</span> <span class="token keyword">return</span> i<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">toList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">var</span> f <span class="token operator">:</span> futures<span class="token punctuation">)</span> f<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"done"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre><p><br><br></p><h2 id="마무리"><a href="#마무리" class="headerlink" title="마무리"></a>마무리</h2><hr><p>자바를 학습하다 보면 JDK 버전, javac/java 명령어, 빌드 툴 같은 개념이 따로따로 나와서 혼란스럽기 쉽다.<br>하지만 큰 그림을 먼저 이해하면 어떤 버전을 쓰든, 어떤 IDE를 쓰든 빠르게 적응할 수 있다.</p>]]></content>
<categories>
<category> 💻 Language </category>
</categories>
<tags>
<tag> Java </tag>
<tag> Spring </tag>
<tag> Gradle </tag>
<tag> Maven </tag>
<tag> IntelliJ </tag>
</tags>
</entry>
<entry>
<title>[HealthCare] HL7 v2 정리</title>
<link href="/2025/02/20/HealthCare/HL7/v2/"/>
<url>/2025/02/20/HealthCare/HL7/v2/</url>
<content type="html"><![CDATA[<h2 id="HL7-표준-정리-레거시부터-최신까지"><a href="#HL7-표준-정리-레거시부터-최신까지" class="headerlink" title="HL7 표준 정리: 레거시부터 최신까지"></a>HL7 표준 정리: 레거시부터 최신까지</h2><p>헬스데이터 스타트업이라면 반드시 알아야 할 국제 표준이 있다.<br>바로 <strong>HL7 (Health Level Seven)</strong> 이다.<br>이 글에서는 HL7 중 v2의 특징, 그리고 실제 메시지 구조까지 하나하나 정리해봤다.</p><hr><h3 id="1-HL7이란"><a href="#1-HL7이란" class="headerlink" title="1. HL7이란"></a>1. HL7이란</h3><ul><li>의료기관의 전산 시스템이 서로 정보를 주고받을 수 있게 해주는 <strong>국제 표준 언어</strong>이다.</li><li>환자 등록, 검사 결과, 처방, 영상 리포트, 보험 청구 등 모든 데이터 교환에 활용된다.</li><li>즉, 병원 간 “공통된 언어” 역할을 한다.</li></ul><hr><h3 id="2-HL7-v2-레거시지만-여전히-현역에서-활발히-사용-중"><a href="#2-HL7-v2-레거시지만-여전히-현역에서-활발히-사용-중" class="headerlink" title="2. HL7 v2 (레거시지만 여전히 현역에서 활발히 사용 중)"></a>2. HL7 v2 (레거시지만 여전히 현역에서 활발히 사용 중)</h3><p>HL7 v2는 1980년대부터 지금까지 가장 널리 사용되는 의료 데이터 교환 표준이다.<br>메시지는 여러 줄로 이루어져 있으며, 각 줄은 <strong>세그먼트(segment)</strong> 라고 부른다.<br>각 세그먼트는 <code>|</code> 기호로 구분된 필드들로 구성된다.</p><h4 id="1-HL7-v2-메시지의-큰-구조"><a href="#1-HL7-v2-메시지의-큰-구조" class="headerlink" title="1) HL7 v2 메시지의 큰 구조"></a>1) HL7 v2 메시지의 큰 구조</h4><p>대표적인 검사결과 메시지(ORU^R01)는 다음 순서로 세그먼트들이 온다.</p><pre class="language-text" data-language="text"><code class="language-text">MSH → PID → PV1 → OBR → OBX</code></pre><ul><li><strong>MSH (Message Header)</strong> : 메시지 전체의 헤더</li><li><strong>PID (Patient Identification)</strong> : 환자 정보</li><li><strong>PV1 (Patient Visit)</strong> : 입원/외래 방문 정보</li><li><strong>OBR (Observation Request)</strong> : 검사/관찰 요청 정보</li><li><strong>OBX (Observation Result)</strong> : 검사/관찰 결과</li></ul><blockquote><p>참고: 상황에 따라 ORC(주문 공통 정보), NTE(메모/주석) 같은 세그먼트가 추가될 수 있다.</p></blockquote><h4 id="2-주요-세그먼트-역할"><a href="#2-주요-세그먼트-역할" class="headerlink" title="2) 주요 세그먼트 역할"></a>2) 주요 세그먼트 역할</h4><table><thead><tr><th>세그먼트</th><th>풀네임</th><th>역할</th></tr></thead><tbody><tr><td><strong>MSH</strong></td><td>Message Header</td><td>메시지 메타데이터: 보낸/받는 시스템, 메시지 타입, 버전 등</td></tr><tr><td><strong>PID</strong></td><td>Patient Identification</td><td>환자 ID, 이름, 생년월일, 성별, 연락처</td></tr><tr><td><strong>PV1</strong></td><td>Patient Visit</td><td>입원/외래 방문 정보 (병동, 병실, 주치의, 방문 번호 등)</td></tr><tr><td><strong>ORC</strong></td><td>Common Order</td><td>검사/처방 등 주문에 대한 공통 정보</td></tr><tr><td><strong>OBR</strong></td><td>Observation Request</td><td>특정 검사 요청 정보 (검사명, 요청자, 시각 등)</td></tr><tr><td><strong>OBX</strong></td><td>Observation Result</td><td>실제 검사/관찰 결과 값</td></tr><tr><td><strong>NTE</strong></td><td>Notes</td><td>주석이나 부가 설명</td></tr></tbody></table><h4 id="3-실제-예시-혈압-검사-결과-메시지"><a href="#3-실제-예시-혈압-검사-결과-메시지" class="headerlink" title="3) 실제 예시: 혈압 검사 결과 메시지"></a>3) 실제 예시: 혈압 검사 결과 메시지</h4><pre class="language-text" data-language="text"><code class="language-text">MSH|^~\&|HIS|HOSP_A|LAB|HOSP_B|202508261030||ORU^R01|MSG0001|P|2.9PID|1||12345^^^HOSP_A||Kim^Minjun||19900101|M|||Seoul^^KR||010-1234-5678PV1|1|I|WARD^101^1^HOSP_A||||1234^Lee^DoctorOBR|1|||BP^Blood Pressure^LN|||202508261030OBX|1|NM|8480-6^Systolic BP^LN||120|mm[Hg]|90-140|N|||F||202508261030OBX|2|NM|8462-4^Diastolic BP^LN||80|mm[Hg]|60-90|N|||F||202508261030</code></pre><h4 id="4-세그먼트별-해설"><a href="#4-세그먼트별-해설" class="headerlink" title="4) 세그먼트별 해설"></a>4) 세그먼트별 해설</h4><ul><li><p><strong>1) MSH (Message Header)</strong>: <code>MSH|^~\&|HIS|HOSP_A|LAB|HOSP_B|202508261030||ORU^R01|MSG0001|P|2.9</code></p><ul><li><code>HIS</code> = 보내는 애플리케이션 (병원 전산 시스템, HIS)</li><li><code>^~\&</code> = 데이터를 어떻게 나눠야 하는지 알려주는 구분자.</li><li><code>HOSP_A</code> = 보내는 기관 (병원 A)</li><li><code>LAB</code> = 받는 애플리케이션 (검사실 시스템)</li><li><code>HOSP_B</code> = 받는 기관 (병원 B)</li><li><code>202508261030</code> = 메시지 생성 시각</li><li><code>ORU^R01</code> = 메시지 타입 (Observation Result, 검사 결과 보고)</li><li><code>MSG0001</code> = 메시지 컨트롤 ID (메시지 고유 식별자)</li><li><code>P</code> = 운영 모드 (Production)</li><li><code>2.9</code> = HL7 버전</li></ul></li><li><p><strong>PID (Patient Identification, 환자 정보)</strong>: <code>PID|1||12345^^^HOSP_A||Kim^Minjun||19900101|M|||Seoul^^KR||010-1234-5678</code></p><ul><li><code>12345^^^HOSP_A</code> = 환자 ID(12345), 발급 기관=HOSP_A</li><li><code>Kim^Minjun</code> = 환자 이름 (성=Kim, 이름=Minjun)</li><li><code>19900101</code> = 환자 생년월일 (1990년 01월 01일)</li><li><code>M</code> = 성별 (Male, 남자)</li><li><code>Seoul^^KR</code> = 주소 (서울, 대한민국)</li><li><code>010-1234-5678</code> = 환자 연락처</li></ul></li><li><p><strong>PV1 (Patient Visit, 환자 방문 정보)</strong>: <code>PV1|1|I|WARD^101^1^HOSP_A||||1234^Lee^Doctor</code></p><ul><li><code>I</code> = 방문 유형 (Inpatient, 입원)</li><li><code>WARD^101</code> = 병동/병실 (101호)</li><li><code>Lee^Doctor</code> = 담당 의사</li></ul></li><li><p><strong>OBR (Observation Request, 검사 요청)</strong>: <code>OBR|1|||BP^Blood Pressure^LN|||202508261030</code></p><ul><li><code>BP^Blood Pressure^LN</code> = 검사 항목: 혈압 (코드=BP, 표시명=Blood Pressure, 코드체계=LOINC: LN)</li><li><code>202508261030</code> = 검사 요청 시각</li></ul></li><li><p><strong>OBX (Observation Result, 검사 결과) - 수축기 혈압</strong>: <code>OBX|1|NM|8480-6^Systolic BP^LN||120|mm[Hg]|90-140|N|||F||202508261030</code></p><ul><li><code>NM</code> = Numeric, 값은 숫자</li><li><code>8480-6^Systolic BP^LN</code> = 수축기 혈압, LOINC 코드 8480-6</li><li><code>120</code> = 측정값</li><li><code>mm[Hg]</code> = 단위 (밀리미터 수은주)</li><li><code>90-140</code> = 참고 범위</li><li><code>N</code> = 정상 (Normal)</li><li><code>F</code> = Final (최종 결과)</li><li><code>202508261030</code> = 결과 생성 시각</li></ul></li><li><p><strong>OBX (Observation Result, 검사 결과) - 이완기 혈압</strong>: <code>OBX|2|NM|8462-4^Diastolic BP^LN||80|mm[Hg]|60-90|N|||F||202508261030</code></p><ul><li><code>NM</code> = Numeric</li><li><code>8462-4^Diastolic BP^LN</code> = 이완기 혈압, LOINC 코드 8462-4</li><li><code>80</code> = 측정값</li><li><code>mm[Hg]</code> = 단위</li><li><code>60-90</code> = 참고 범위</li><li><code>N</code> = 정상</li><li><code>F</code> = Final (최종 결과)</li><li><code>202508261030</code> = 결과 생성 시각</li></ul></li></ul><hr><h3 id="HL7-v2-요약"><a href="#HL7-v2-요약" class="headerlink" title="HL7 v2 요약"></a>HL7 v2 요약</h3><ul><li>HL7 v2 메시지는 여러 세그먼트로 구성된 텍스트 메시지이다.</li><li><strong>MSH → PID → PV1 → OBR → OBX</strong> 순으로<br>환자 정보, 방문 정보, 검사 요청, 검사 결과가 기록된다.</li><li>OBX는 실제 결과 값을 담는 부분일 뿐, 항상 <strong>앞뒤 세그먼트와 함께 묶여서</strong> 온다.</li><li>이 구조를 이해하면 HL7 메시지를 해석하고, 병원 EHR 시스템에 맞게 매핑할 수 있다.</li></ul>]]></content>
<categories>
<category> 🏥 HealthCare </category>
</categories>
<tags>
<tag> EHR </tag>
<tag> HL7 </tag>
<tag> SDC </tag>
<tag> HealthCare </tag>
</tags>
</entry>
<entry>
<title>[HealthCare] EHR 연동: HL7 / IEEE 11073 SDC 총정리</title>
<link href="/2025/01/10/HealthCare/EHR-FHIR-SDC/standard/"/>
<url>/2025/01/10/HealthCare/EHR-FHIR-SDC/standard/</url>
<content type="html"><![CDATA[<h2 id="EHR-연동-HL7-IEEE-11073-SDC-올인원-정리"><a href="#EHR-연동-HL7-IEEE-11073-SDC-올인원-정리" class="headerlink" title="EHR 연동: HL7 / IEEE 11073 SDC 올인원 정리"></a>EHR 연동: HL7 / IEEE 11073 SDC 올인원 정리</h2><p>나는 이래봬도 의료데이터를 활용해서 개발하는 사람인데, 최근 부트캠프 멘토링을 하다보면 의료기술 쪽으로 프로그램이 많이 생기길래 정리해두면 좋겠다 싶어 글을 작성해봤다.</p><p>의료데이터 스타트업을 운영하거나, 병원과 시스템을 연동하려 한다면 반드시 알아야 할 것이 있다.<br>바로 <strong>HL7</strong>과 <strong>IEEE 11073 SDC</strong>이다. 이 글에서는 두 표준이 무엇인지, 어떻게 쓰이는지, 그리고 최신 동향까지 한 번에 정리하였다.</p><hr><h3 id="1-EHR이란-무엇인가"><a href="#1-EHR이란-무엇인가" class="headerlink" title="1. EHR이란 무엇인가"></a>1. EHR이란 무엇인가</h3><ul><li><strong>EHR (Electronic Health Record)</strong> 는 전자의무기록 시스템을 말한다.</li><li>환자의 진료기록, 검사결과, 처방, 영상 등 모든 의료 데이터를 담는다.</li><li>문제는 병원마다 시스템과 기기가 제각각이라서 서로 데이터를 주고받기 어렵다는 점이다.</li><li>그래서 <strong>국제 표준 언어</strong>가 필요하게 되었다. 이게 바로 HL7의 탄생 계기이다.</li></ul><hr><h3 id="2-HL7-병원-시스템-간-언어"><a href="#2-HL7-병원-시스템-간-언어" class="headerlink" title="2. HL7: 병원 시스템 간 언어"></a>2. HL7: 병원 시스템 간 언어</h3><ul><li><strong>HL7 (Health Level Seven)</strong> 은 병원 전산끼리 정보를 주고받는 국제 표준이다.</li><li><strong>HL7 v2</strong>는 1980년대부터 쓰였고, 여전히 대부분의 병원에서 사용한다.</li><li><strong>HL7 v3</strong>는 XML 기반으로 복잡하여 널리 퍼지지 못했다.</li><li><strong>FHIR (Fast Healthcare Interoperability Resources)</strong> 는 최신 표준으로 JSON과 API 기반이라 현대적인 시스템과 잘 맞는다.</li><li>요약하자면 <strong>옛날에는 텍스트, 중간에는 XML, 지금은 JSON(FHIR)</strong> 시대라고 할 수 있다.</li></ul><hr><h3 id="3-IEEE-11073-SDC-의료기기-연결-언어"><a href="#3-IEEE-11073-SDC-의료기기-연결-언어" class="headerlink" title="3. IEEE 11073 SDC: 의료기기 연결 언어"></a>3. IEEE 11073 SDC: 의료기기 연결 언어</h3><ul><li><strong>SDC (Service-oriented Device Connectivity)</strong> 는 의료기기를 네트워크에 연결하기 위한 국제 표준이다.</li><li>의료기기가 “나는 혈압 데이터를 제공한다” “나는 산소포화도를 알려줄 수 있다”와 같이 스스로 기능을 설명할 수 있게 정의하였다.</li><li>환자 모니터, 인퓨전 펌프, 수술 장비 등 다양한 기기가 SDC를 통해 안전하게 데이터를 주고받는다.</li><li>단순한 측정값 전송뿐 아니라 알림, 원격 제어까지 지원한다.</li><li>보안은 <strong>TLS와 X.509 인증서</strong>를 통해 이루어진다.</li></ul><hr><h3 id="4-HL7-SDC-조합-왜-필요한가"><a href="#4-HL7-SDC-조합-왜-필요한가" class="headerlink" title="4. HL7 + SDC 조합: 왜 필요한가"></a>4. HL7 + SDC 조합: 왜 필요한가</h3><ul><li>병원에는 수많은 기기가 있고, 각각이 데이터를 쏟아낸다.</li><li>각 병원마다 데이터 세팅이 다르기 때문에, 이 데이터를 EHR에 직접 연결하면 포맷 충돌과 오류가 발생한다. 그래서 중간에서 standard 구조로 리팩토링을 해줘야 알아서들 편하게 데이터를 다룰 수 있다.</li><li>그래서 <strong>구조는 이렇게 나뉜다</strong>:<pre class="language-text" data-language="text"><code class="language-text">[의료기기] --SDC--> [게이트웨이] --HL7/FHIR--> [EHR]</code></pre><ul><li>의료기기: 혈압 120/80 mmHg 데이터를 생성한다.</li><li>SDC 게이트웨이: 이를 SDC 언어로 받아 HL7/FHIR로 변환한다.</li><li>EHR: 변환된 데이터를 환자 기록에 저장한다.</li></ul></li></ul><hr><h3 id="5-실제-데이터-흐름-예시"><a href="#5-실제-데이터-흐름-예시" class="headerlink" title="5. 실제 데이터 흐름 예시"></a>5. 실제 데이터 흐름 예시</h3><h4 id="1-SDC에서-나온-값"><a href="#1-SDC에서-나온-값" class="headerlink" title="1) SDC에서 나온 값"></a>1) SDC에서 나온 값</h4><pre class="language-text" data-language="text"><code class="language-text">Metric: BloodPressureValue: 120/80Unit: mmHg</code></pre><h4 id="2-게이트웨이가-변환한-FHIR-JSON"><a href="#2-게이트웨이가-변환한-FHIR-JSON" class="headerlink" title="2) 게이트웨이가 변환한 FHIR(JSON)"></a>2) 게이트웨이가 변환한 FHIR(JSON)</h4><pre class="language-json" data-language="json"><code class="language-json"><span class="token punctuation">{</span> <span class="token property">"resourceType"</span><span class="token operator">:</span> <span class="token string">"Observation"</span><span class="token punctuation">,</span> <span class="token property">"subject"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"reference"</span><span class="token operator">:</span> <span class="token string">"Patient/12345"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"device"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"reference"</span><span class="token operator">:</span> <span class="token string">"Device/dev-mds-01"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"effectiveDateTime"</span><span class="token operator">:</span> <span class="token string">"2025-08-26T10:30:00+09:00"</span><span class="token punctuation">,</span> <span class="token property">"status"</span><span class="token operator">:</span> <span class="token string">"final"</span><span class="token punctuation">,</span> <span class="token property">"code"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"coding"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token property">"system"</span><span class="token operator">:</span> <span class="token string">"http://loinc.org"</span><span class="token punctuation">,</span> <span class="token property">"code"</span><span class="token operator">:</span> <span class="token string">"85354-9"</span><span class="token punctuation">,</span> <span class="token property">"display"</span><span class="token operator">:</span> <span class="token string">"Blood pressure panel"</span> <span class="token punctuation">}</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"component"</span><span class="token operator">:</span> <span class="token punctuation">[</span> <span class="token punctuation">{</span> <span class="token property">"code"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"coding"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token property">"system"</span><span class="token operator">:</span> <span class="token string">"http://loinc.org"</span><span class="token punctuation">,</span> <span class="token property">"code"</span><span class="token operator">:</span> <span class="token string">"8480-6"</span><span class="token punctuation">,</span> <span class="token property">"display"</span><span class="token operator">:</span> <span class="token string">"Systolic blood pressure"</span> <span class="token punctuation">}</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"valueQuantity"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token number">120</span><span class="token punctuation">,</span> <span class="token property">"unit"</span><span class="token operator">:</span> <span class="token string">"mmHg"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token property">"code"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"coding"</span><span class="token operator">:</span> <span class="token punctuation">[</span><span class="token punctuation">{</span> <span class="token property">"system"</span><span class="token operator">:</span> <span class="token string">"http://loinc.org"</span><span class="token punctuation">,</span> <span class="token property">"code"</span><span class="token operator">:</span> <span class="token string">"8462-4"</span><span class="token punctuation">,</span> <span class="token property">"display"</span><span class="token operator">:</span> <span class="token string">"Diastolic blood pressure"</span> <span class="token punctuation">}</span><span class="token punctuation">]</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token property">"valueQuantity"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"value"</span><span class="token operator">:</span> <span class="token number">80</span><span class="token punctuation">,</span> <span class="token property">"unit"</span><span class="token operator">:</span> <span class="token string">"mmHg"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">]</span><span class="token punctuation">}</span></code></pre><hr><h3 id="6-최신-버전-기준"><a href="#6-최신-버전-기준" class="headerlink" title="6. 최신 버전 기준"></a>6. 최신 버전 기준</h3><ul><li><strong>HL7 v2:</strong> 2.9.1 (2024)</li><li><strong>FHIR:</strong> R5 (2023, 최신 안정판)</li><li><strong>IEEE 11073 SDC:</strong><ul><li>10207 (BICEPS, 데이터 모델)</li><li>20702 (MDPWS, 통신)</li><li>20701 (아키텍처 바인딩)</li></ul></li></ul><hr><h3 id="7-정리"><a href="#7-정리" class="headerlink" title="7. 정리"></a>7. 정리</h3><ul><li><strong>HL7/FHIR</strong>은 병원 전산끼리 소통하는 언어이다.</li><li><strong>SDC</strong>는 의료기기끼리 소통하는 언어이다.</li><li><strong>게이트웨이</strong>는 두 언어를 번역한다.</li><li>최신 연동은 <strong>SDC + FHIR</strong> 조합으로 한다.</li><li>다만 현실적으로 병원 내부에는 <strong>HL7 v2</strong>도 병행해야 한다.</li><li>이 구조를 이해하면 헬스데이터 스타트업이 병원과 연동하는 모든 흐름을 설계할 수 있다.</li></ul>]]></content>
<categories>
<category> 🏥 HealthCare </category>
</categories>
<tags>
<tag> EHR </tag>
<tag> HL7 </tag>
<tag> IEEE </tag>
<tag> SDC </tag>
<tag> HealthCare </tag>
</tags>
</entry>
<entry>
<title>[Vue.js] Vue3 SEO 최적화하기 (sitemap.map, robots.txt)</title>
<link href="/2025/01/01/Frontend/Vuejs/SEO/"/>
<url>/2025/01/01/Frontend/Vuejs/SEO/</url>
<content type="html"><![CDATA[<p>개발 포트폴리오 사이트를 만들었는데, 배포는 성공했다만 생각해보니 검색 유입을 위한 SEO(Search Engine Optimization) 최적화를 하지 않았음을 깨달았다..<br>따라서 Vue3로 하는 방법을 간략히 정리해보고자 한다.</p><p>참고로 여기서는 각 포털별 세팅은 다루지 않고 <code>sitemap.xml</code>, <code>robots.txt</code> 생성법만 작성했다.<br>포털별 세팅은 인터넷에 검색하면 많이 나오기 때문에 우리 개발 알잘딱 분들은 잘 하실거라 믿는다 ㅎㅎ</p><h2 id="sitemap-xml만들기"><a href="#sitemap-xml만들기" class="headerlink" title="sitemap.xml만들기"></a>sitemap.xml만들기</h2><p>일단 자신의 프로젝트에서 어떤 vue 프레임워크를 사용하는지 잘 알아야 한다.<br>VuePress같은 경우에는 <code>vuepress-plugin-sitemap</code> 패키지를 설치해서 module.exports를 하면 바로되지만,<br>필자는 vue3를 쌩으로 갖다 박았기 때문에 직접 생성을 해야한다. ㅎㅋ… <del>뒤늦게 몰려드는 후회</del><br>왜냐면 플러그인 패키지를 돌리면 아래와 같은 에러가 발생하기 때문이다.</p><pre class="language-bash" data-language="bash"><code class="language-bash">node:internal/modules/esm/get_format:183 throw new ERR_UNKNOWN_FILE_EXTENSION<span class="token punctuation">(</span>ext, filepath<span class="token punctuation">)</span><span class="token punctuation">;</span> ^TypeError <span class="token punctuation">[</span>ERR_UNKNOWN_FILE_EXTENSION<span class="token punctuation">]</span>: Unknown <span class="token function">file</span> extension <span class="token string">".vue"</span> <span class="token keyword">for</span> /Users/rubykim/portfolio/frontend/src/views/Home.vue at Object.getFileProtocolModuleFormat <span class="token punctuation">[</span>as file:<span class="token punctuation">]</span> <span class="token punctuation">(</span>node:internal/modules/esm/get_format:183:9<span class="token punctuation">)</span> at defaultGetFormat <span class="token punctuation">(</span>node:internal/modules/esm/get_format:209:36<span class="token punctuation">)</span> at defaultLoadSync <span class="token punctuation">(</span>node:internal/modules/esm/load:173:14<span class="token punctuation">)</span> at <span class="token comment">#loadAndMaybeBlockOnLoaderThread (node:internal/modules/esm/loader:723:12)</span> at <span class="token comment">#loadSync (node:internal/modules/esm/loader:745:49)</span> at ModuleLoader.getModuleJobForRequire <span class="token punctuation">(</span>node:internal/modules/esm/loader:384:38<span class="token punctuation">)</span> at new ModuleJobSync <span class="token punctuation">(</span>node:internal/modules/esm/module_job:342:34<span class="token punctuation">)</span> at ModuleLoader.importSyncForRequire <span class="token punctuation">(</span>node:internal/modules/esm/loader:332:11<span class="token punctuation">)</span> at loadESMFromCJS <span class="token punctuation">(</span>node:internal/modules/cjs/loader:1570:24<span class="token punctuation">)</span> at Module._compile <span class="token punctuation">(</span>node:internal/modules/cjs/loader:1722:5<span class="token punctuation">)</span> <span class="token punctuation">{</span> code: <span class="token string">'ERR_UNKNOWN_FILE_EXTENSION'</span><span class="token punctuation">}</span></code></pre><br><p>한줄 요약하자면 <strong>vue파일 인식이 안되네요</strong>라는 말이므로, 결국 노가다를 해야한다는 뜻이다.<br>다행히도 노가다 코드는 매우 간단한 편이다.</p><p>먼저 패키지를 설치해준 후,</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">npm</span> <span class="token function">install</span> sitemap</code></pre><br><p>코드를 다음과 같이 세팅해주면 된다.</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// generate-sitemap.js</span><span class="token keyword">const</span> <span class="token punctuation">{</span> SitemapStream<span class="token punctuation">,</span> streamToPromise <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"sitemap"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> <span class="token punctuation">{</span> createWriteStream <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"fs"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> <span class="token punctuation">{</span> resolve <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token function">require</span><span class="token punctuation">(</span><span class="token string">"path"</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">const</span> routes <span class="token operator">=</span> <span class="token punctuation">[</span> <span class="token comment">// 여기에서 모든 page의 url입력</span> <span class="token punctuation">{</span> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">"/"</span><span class="token punctuation">,</span> <span class="token literal-property property">priority</span><span class="token operator">:</span> <span class="token number">1.0</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">"/about"</span><span class="token punctuation">,</span> <span class="token literal-property property">priority</span><span class="token operator">:</span> <span class="token number">0.9</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">{</span> <span class="token literal-property property">path</span><span class="token operator">:</span> <span class="token string">"/contact"</span><span class="token punctuation">,</span> <span class="token literal-property property">priority</span><span class="token operator">:</span> <span class="token number">0.9</span> <span class="token punctuation">}</span><span class="token punctuation">,</span><span class="token punctuation">]</span><span class="token punctuation">;</span><span class="token keyword">const</span> sitemap <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">SitemapStream</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">hostname</span><span class="token operator">:</span> <span class="token operator"><</span>실제_배포_사이트_url<span class="token operator">></span><span class="token punctuation">,</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token function">streamToPromise</span><span class="token punctuation">(</span> routes <span class="token punctuation">.</span><span class="token function">reduce</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">stream<span class="token punctuation">,</span> route</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> stream<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">url</span><span class="token operator">:</span> route<span class="token punctuation">.</span>path<span class="token punctuation">,</span> <span class="token literal-property property">changefreq</span><span class="token operator">:</span> <span class="token string">"monthly"</span><span class="token punctuation">,</span> <span class="token literal-property property">priority</span><span class="token operator">:</span> route<span class="token punctuation">.</span>priority<span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> stream<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> sitemap<span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">end</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token parameter">data</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> outputPath <span class="token operator">=</span> <span class="token function">resolve</span><span class="token punctuation">(</span>__dirname<span class="token punctuation">,</span> <span class="token string">"dist/sitemap.xml"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">const</span> writeStream <span class="token operator">=</span> <span class="token function">createWriteStream</span><span class="token punctuation">(</span>outputPath<span class="token punctuation">)</span><span class="token punctuation">;</span> writeStream<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span>data<span class="token punctuation">.</span><span class="token function">toString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> writeStream<span class="token punctuation">.</span><span class="token function">end</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><br><p>이 파일을 설정해줬다면 <code>package.json</code>의 build script에 sitemap 생성 명령어를 같이 입력해주자.</p><pre class="language-json" data-language="json"><code class="language-json">...<span class="token property">"scripts"</span><span class="token operator">:</span> <span class="token punctuation">{</span> <span class="token property">"build"</span><span class="token operator">:</span> <span class="token string">"vue-cli-service build && node generate-sitemap.js"</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">,</span>...</code></pre><p><br><br><br></p><h2 id="robots-txt-만들기"><a href="#robots-txt-만들기" class="headerlink" title="robots.txt 만들기"></a>robots.txt 만들기</h2><p>robots.txt는 만들기 매우 쉽다. 그냥 txt 파일을 갖다 넣으면 되기 때문이다.<br>다만 여기서 중요한 것이 있는데, <strong>웹사이트 루트 디렉토리</strong>에 위치해야 한다는 것이다.</p><p>특별한 프로젝트 구조가 아닌 이상, 대부분 <code>public</code>폴더에 robots.txt를 만들어놓으면 build시 자동으로 루트 디렉토리에 해당 파일이 위치하게 될 것이다.<br>아래는 robots.txt 예시이다.</p><pre class="language-txt" data-language="txt"><code class="language-txt">User-agent: *Disallow:Sitemap: <실제_배포_사이트_url>/sitemap.xml</code></pre><p>필자는 포트폴리오 사이트에 대해서 SEO를 설정하고 있기 때문에, Disallow를 따로 세팅하지는 않았다.<br>만약 개발 중인 페이지나 검색 결과에 나타나기 원하지 않는 콘텐츠가 있다면, Disallow에 넣어주도록 하자.</p><p><br><br><br></p><h2 id="결과물"><a href="#결과물" class="headerlink" title="결과물"></a>결과물</h2><img src="./1.png" width="800"><img src="./2.png" width="800">]]></content>
<categories>
<category> ✨ Frontend </category>
</categories>
<tags>
<tag> Javascript </tag>
<tag> Frontend </tag>
<tag> Vue </tag>
<tag> SEO </tag>
</tags>
</entry>
<entry>
<title>[Next.js] 배포하기: AWS Amplify vs Github pages vs fly.io vs Vercel vs Netlify</title>
<link href="/2024/12/29/Frontend/Nextjs/Deployment/"/>
<url>/2024/12/29/Frontend/Nextjs/Deployment/</url>
<content type="html"><![CDATA[<p>프로젝트를 하다보면 언젠가 배포를 해야 하는 순간이 온다.</p><p>필자 또한 최근 nextJS로 간단한 홈페이지를 만들었는데, 막상 배포를 하려니 nextJS라 고려해야할 점이 많아서 한 번 정리해보고자 한다.</p><p>결론만 볼 사람들은 5번으로 바로 넘어가면 된다.</p><h2 id="NextJS를-선택한-이유는"><a href="#NextJS를-선택한-이유는" class="headerlink" title="(NextJS를 선택한 이유는?)"></a>(NextJS를 선택한 이유는?)</h2><p>일단 플랫폼을 비교하기 앞서서 굳이 nextJS를 선택한 이유를 간단히 적어보자 한다.<br>그래야 비교하는 의미가 있기 때문이다.</p><p>NextJS는 <code>SSR(서버 사이드 랜더링)</code>을 목적으로 주로 선택되는 웹 프레임워크이다.<br>즉 각 페이지를 서버 측에서 먼저 렌더링을 할 수 있기 때문에, 초기 페이지 로딩 속도가 빠르고 <code>SEO(검색 엔진 최적화)</code>에 매우 유리하다.<br>필자 또한 만든 프로그램이 인터넷 검색이 잘 되도록 하고 싶어서, 고민없이 바로 nextJS를 선택했다.</p><h2 id="1-❌-AWS-Amplify"><a href="#1-❌-AWS-Amplify" class="headerlink" title="1. ❌ AWS Amplify"></a>1. ❌ AWS Amplify</h2><img src="./1.png" width="800"><p>필자는 회사 업무로 인해 AWS를 주로 사용하는데, 생각해보니 AWS CloudFront를 직접 설정해서 프론트엔드를 배포했지, Amplify는 써본 적이 없어서 연습 겸 여기로 호스팅을 시도를 했다.</p><p>물론 어찌저찌 하니 배포는 잘 됐는데, 문제가 발생했다.<br>크게 2가지 문제가 있었는데, 바로 <code>배포/반영 시간이 너무 걸린다</code>는 것이다.</p><p>Amplify는 CDN을 위해 CloudFront를 사용하는데, CloudFront는 CDN과 Compute@Edge 배포에서 invalidations(무효화)와 propagations(전파)를 지원하지 않아 일종의 <strong>병목현상</strong>이 나타난 것이었다.</p><p>필자가 구현한 프로젝트가 간단한 편에 속하는데, 실제로 배포 후 반영까지 약 20분이라는 시간이 걸렸다. 실로 놀라울 따름…</p><br><p>또 하나의 문제는 <code>이미지 로드가 느리다는 것</code>이었다.<br>현재 기준으로 region을 <strong>us-east-1</strong>(버지니아 북부)로만 설정할 수 있는데, 파일 내부 static 이미지들이 캐싱되기 전까지는 이미지 로드가 매우 느리다는 것이었다.</p><p>맨 처음에 이미지 로딩 시간이 너무 길어보여서 착각한건가 싶어 몇 번 재테스트를 했는데,<br>그럼에도 불구하고 확실하게 정적 이미지들이 캐싱되기 전까지는 느리게 불러와지는 모습에 한탄을 금치 못했다.</p><p>눈물 머금고 나의 작고 귀여운 돈을 바치겠다는데 이렇게까지 느릴 일이 있나? 싶어서 결국 던지게 되었다 ㅎㅎ</p><p><br><br></p><h2 id="2-❌-Github-Pages"><a href="#2-❌-Github-Pages" class="headerlink" title="2. ❌ Github Pages"></a>2. ❌ Github Pages</h2><img src="./2.jpg" width="800"><p>사실 이거는 시도조차 안했다. 왜냐면 이 블로그 자체가 Github Pages로 운영되고 있기 때문에 굳이 동일한 기술 스택을 사용해야 하나 싶었기 때문이다.</p><p>무엇보다 Github Pages를 포기한 이유가 바로 <code>API 라우트</code> 였다. 안타깝게도 <strong>Github Pages는 서버 이용이 불가능</strong>한데, 나는 API 라우트를 구현했기 때문이다. 서버 없이 어떻게 작동시키겠어…ㅠㅜ</p><p>따라서 API 라우트 없는 build 결과물로는 github pages 배포는 가능하지만, API 라우트를 사용한다면 100% github pages에서 서비스가 안돌아가기 때문이 다른 대안점을 찾아야 했다.</p><p><br><br></p><h2 id="3-✅-fly-io"><a href="#3-✅-fly-io" class="headerlink" title="3. ✅ fly.io"></a>3. ✅ fly.io</h2><img src="./3.png" width="800"><p><a href="https://fly.io/">fly.io</a>는 컨테이너 기반 애플리케이션으로, 전 세계 여러 데이터 센터에서 애플리케이션을 자동으로 배포하여 지연 시간을 최소화 및 성능 최적화가 가능한 플랫폼이다.</p><p>클라우드에서 Container Registry에 이미지를 업로드하여 Kubernetes로 돌리는건 흔한 경우라, 이것도 체험을 해보고 싶어서 가볍게 업로드를 해봤다.</p><p>명령어를 써야한대서 어렵나 싶었는데, 생각보다 나쁘지 않았다. 아래 명령어가 전부이기 때문이다.<br>하지만 이 프로그램은 아쉽게도 최종 후보에서 탈락하고 말았다. 왜냐면 무료기간 이후로 매달 25달러를 내야하기 때문이다 <del>돈아끼기</del></p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 1. flyctl 설치</span><span class="token comment">## brew 설치</span>brew <span class="token function">install</span> flyctl<span class="token comment">## brew사용이 어려울 시</span><span class="token function">curl</span> <span class="token parameter variable">-L</span> https://fly.io/install.sh <span class="token operator">|</span> <span class="token function">sh</span><span class="token comment"># 2. flyctl 로그인</span>flyctl auth login<span class="token comment"># 3. 초기 설정 및 배포하기</span><span class="token comment">## 이때 fly.toml 및 Dockerfile이 생성되며, 자동으로 배포가 진행됨</span>fly launch<span class="token comment"># 4. 이후 코드 수정 후 배포 업데이트</span>fly deploy</code></pre><p><br><br></p><h2 id="4-✅-Vercel-vs-Netlify"><a href="#4-✅-Vercel-vs-Netlify" class="headerlink" title="4. ✅ Vercel vs Netlify"></a>4. ✅ Vercel vs Netlify</h2><img src="./4.avif" width="800"><p>이 두 친구들은 프론트엔드 배포를 하는데 많이 사용되는 플랫폼이다.<br>왜냐면 배포도 매우 쉽고 무엇보다 <strong>무료</strong> 범위 내에서 충분히 커버할 수 있기 때문이다.</p><p>따라서 이 둘을 두고 어디로 배포를 하냐 의견이 분분히 발생하는데, 간단하게 정리를 해보고자 한다.<br>(참고: <a href="https://ikius.com/blog/vercel-vs-netlify">https://ikius.com/blog/vercel-vs-netlify</a>)</p><h4 id="Vercel"><a href="#Vercel" class="headerlink" title="Vercel"></a>Vercel</h4><ul><li>nextJS에 한정해서 최적의 배포가 가능: vercel에서 nextjs를 만들었기 때문</li><li>빠른 로딩 속도</li></ul><h4 id="Netlify"><a href="#Netlify" class="headerlink" title="Netlify"></a>Netlify</h4><ul><li>다양한 정적 사이트 생성기 & 복잡한 배포 요구사항이 있을 경우에 사용이 좋음: vercel보다 플러그인이 많이 제공되기 때문</li><li>무료 플랜에서 상업 용도로 사용 가능 (vercel은 상업용으로 페이지 만들 시 플랜 구매 필요)</li></ul><p><br><br></p><h2 id="5-결론"><a href="#5-결론" class="headerlink" title="5. 결론"></a>5. 결론</h2><p>합리적인 가격(무료 또는 소액)으로 배포를 한다는 가정하에,<br><code>Vercel</code>, <code>Netlify</code>, <code>fly.io</code>를 추천한다!</p><p>Github Pages는 NextJS에서 API 라우트를 구현하지 않았을 때만 추천한다.</p>]]></content>
<categories>
<category> ✨ Frontend </category>
</categories>
<tags>
<tag> NextJS </tag>
<tag> Javascript </tag>
<tag> Frontend </tag>
</tags>
</entry>
<entry>
<title>[GCP] GCP에서 사용자 인증정보(OAuth)를 사용해 Access Token 받아오기</title>
<link href="/2024/12/20/Cloud/GCP/Console/Oauth2/"/>
<url>/2024/12/20/Cloud/GCP/Console/Oauth2/</url>
<content type="html"><![CDATA[<p>Google Calendar에 커피챗 일정을 잡아주는 프로그램을 만드는 중인데, 이 과정에서 Google Calendar API를 사용하기 위해서는 GCP로부터 Access Token 발급을 받아야 하므로 그 방법을 한 번 정리해보자고 한다.<br><code>scope</code>부분만 원하는 서비스로 선택하면 해당 서비스의 Access Token을 받을 수 있으며 여기서는 내가 작업 중인 Google Calendar를 예시로 글을 작성해본다.</p><h2 id="1-GCP-API-및-서비스-사용자-인증-정보에서-OAuth-client-생성"><a href="#1-GCP-API-및-서비스-사용자-인증-정보에서-OAuth-client-생성" class="headerlink" title="1. GCP > API 및 서비스 > 사용자 인증 정보에서 OAuth client 생성"></a>1. GCP > API 및 서비스 > 사용자 인증 정보에서 OAuth client 생성</h2><img src="./1.png" width="800"><p>이번 포스트에서는 클라이언트 생성 방법보다는 Access Token발급을 중점으로 다루고 있기 때문에 client 세팅 방법은 따로 안내하지 않겠다.</p><p>여기에서 우리가 확인해야 할 정보는 다음과 같다.</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token assign-left variable">GOOGLE_CLIENT_ID</span><span class="token operator">=</span><span class="token operator"><</span>클라이언트 ID<span class="token operator">></span><span class="token assign-left variable">GOOGLE_CLIENT_SECRET</span><span class="token operator">=</span><span class="token operator"><</span>클라이언트 보안 비밀번호<span class="token operator">></span><span class="token assign-left variable">GOOGLE_REDIRECT_URI</span><span class="token operator">=</span><span class="token operator"><</span>승인된 리디렉션 URI주소<span class="token operator">></span></code></pre><p><br><br></p><h2 id="2-Google-Calender의-Access-Token요청을-위한-URL-입력"><a href="#2-Google-Calender의-Access-Token요청을-위한-URL-입력" class="headerlink" title="2. Google Calender의 Access Token요청을 위한 URL 입력"></a>2. Google Calender의 Access Token요청을 위한 URL 입력</h2><p>아무 인터넷 창에다가 다음의 url을 입력한다.</p><pre class="language-bash" data-language="bash"><code class="language-bash">https://accounts.google.com/o/oauth2/v2/auth?scope<span class="token operator">=</span>https://www.googleapis.com/auth/calendar<span class="token operator">&</span><span class="token assign-left variable">access_type</span><span class="token operator">=</span>offline<span class="token operator">&</span><span class="token assign-left variable">include_granted_scopes</span><span class="token operator">=</span>true<span class="token operator">&</span><span class="token assign-left variable">response_type</span><span class="token operator">=</span>code<span class="token operator">&</span><span class="token assign-left variable">redirect_uri</span><span class="token operator">=</span><span class="token operator"><</span>GOOGLE_REDIRECT_URI<span class="token operator">>&</span><span class="token assign-left variable">client_id</span><span class="token operator">=</span><span class="token operator"><</span>GOOGLE_CLIENT_ID<span class="token operator">></span></code></pre><img src="./2.png" width="800"><img src="./3.png" width="800"><p>값이 잘 입력됐다면 google 계정으로 로그인이 나오며, 액세스 허용 여부를 물어보는 페이지를 볼 수 있다.</p><p><br><br></p><h2 id="3-Redirect-uri로-받아온-값-확인"><a href="#3-Redirect-uri로-받아온-값-확인" class="headerlink" title="3. Redirect uri로 받아온 값 확인"></a>3. Redirect uri로 받아온 값 확인</h2><p>위 이미지에서 “허용” 버튼을 누르면 redirect uri로 바로 이동한다.<br>이 때 주소창을 확인하면 response를 확인할 수 있으며, <code>CODE</code>부분을 잘 백업해두자.<br>코드의 유효시간은 10분인 것 또한 참고할 것</p><pre class="language-bash" data-language="bash"><code class="language-bash">GOOGLE_REDIRECT_URI/?code<span class="token operator">=</span><span class="token operator"><</span>CODE<span class="token operator">>&</span><span class="token assign-left variable">scope</span><span class="token operator">=</span>https://www.googleapis.com/auth/calendar</code></pre><h2 id="4-Access-Token-발급받기"><a href="#4-Access-Token-발급받기" class="headerlink" title="4. Access Token 발급받기"></a>4. Access Token 발급받기</h2><p>이제 Access Token을 발급받을 준비가 되었다.<br>다음의 명령어를 입력해보자. curl이니 터미널에 입력하면 된다.</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">curl</span> <span class="token parameter variable">--request</span> POST <span class="token punctuation">\</span> <span class="token parameter variable">--url</span> https://oauth2.googleapis.com/token <span class="token punctuation">\</span> <span class="token parameter variable">--header</span> <span class="token string">'Content-Type: application/x-www-form-urlencoded'</span> <span class="token punctuation">\</span> <span class="token parameter variable">--data</span> <span class="token string">"code=<CODE>"</span> <span class="token punctuation">\</span> <span class="token parameter variable">--data</span> <span class="token string">"client_id=<GOOGLE_CLIENT_ID>"</span> <span class="token punctuation">\</span> <span class="token parameter variable">--data</span> <span class="token string">"client_secret=<GOOGLE_CLIENT_SECRET>"</span> <span class="token punctuation">\</span> <span class="token parameter variable">--data</span> <span class="token string">"redirect_uri=<GOOGLE_REDIRECT_URI>"</span> <span class="token punctuation">\</span> <span class="token parameter variable">--data</span> <span class="token string">"grant_type=authorization_code"</span></code></pre><br><p>제대로 값이 전달되면 다음과 같은 response를 얻을 수 있다.</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token punctuation">{</span> <span class="token string">"access_token"</span><span class="token builtin class-name">:</span> <span class="token operator"><</span>ACCESS_TOKEN<span class="token operator">></span>, <span class="token string">"expires_in"</span><span class="token builtin class-name">:</span> <span class="token number">3599</span>, <span class="token string">"refresh_token"</span><span class="token builtin class-name">:</span> <span class="token operator"><</span>REFRESH_TOKEN<span class="token operator">></span>, <span class="token string">"scope"</span><span class="token builtin class-name">:</span> <span class="token string">"https://www.googleapis.com/auth/calendar"</span>, <span class="token string">"token_type"</span><span class="token builtin class-name">:</span> <span class="token string">"Bearer"</span><span class="token punctuation">}</span></code></pre><br><h3 id="4-1-Refresh-Token을-사용해서-Access-Token을-재발급-받기"><a href="#4-1-Refresh-Token을-사용해서-Access-Token을-재발급-받기" class="headerlink" title="4-1. Refresh Token을 사용해서 Access Token을 재발급 받기"></a>4-1. Refresh Token을 사용해서 Access Token을 재발급 받기</h3><p>결과를 보면 <code>expires_in</code>이 있는데, 3599초 즉 <code>1시간</code>만 Access Token을 사용할 수 있으며 이후로는 토큰 사용이 불가능하다.</p><p>나처럼 캘린더 일정을 계속 자동화해서 잡아야 하는 경우에는 <code>refresh_token</code>을 이용해서 <code>access_token</code>을 갱신해야 한다.<br>다행이도 Google OAuth2에서 제공하는 <strong>refresh_token</strong>은 만료되지 않는다.</p><br><p>만약 <strong>refresh_token</strong> 을 사용해서 <strong>access_token</strong>을 재발급 받고 싶으면 다음의 curl을 보내주자.</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">curl</span> <span class="token parameter variable">--request</span> POST <span class="token punctuation">\</span> <span class="token parameter variable">--url</span> https://oauth2.googleapis.com/token <span class="token punctuation">\</span> <span class="token parameter variable">--header</span> <span class="token string">'Content-Type: application/x-www-form-urlencoded'</span> <span class="token punctuation">\</span> <span class="token parameter variable">--data</span> <span class="token string">"client_id=<GOOGLE_CLIENT_ID>"</span> <span class="token punctuation">\</span> <span class="token parameter variable">--data</span> <span class="token string">"client_secret=<GOOGLE_CLIENT_SECRET>"</span> <span class="token punctuation">\</span> <span class="token parameter variable">--data</span> <span class="token string">"refresh_token=<REFRESH_TOKEN>"</span> <span class="token punctuation">\</span> <span class="token parameter variable">--data</span> <span class="token string">"grant_type=refresh_token"</span></code></pre><br><p>갱신 요청이 성공하면 새로운 <code>access_token</code>이 반환된다.</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token punctuation">{</span> <span class="token string">"access_token"</span><span class="token builtin class-name">:</span> <span class="token operator"><</span>ACCESS_TOKEN<span class="token operator">></span>, <span class="token string">"expires_in"</span><span class="token builtin class-name">:</span> <span class="token number">3599</span>, <span class="token string">"scope"</span><span class="token builtin class-name">:</span> <span class="token string">"https://www.googleapis.com/auth/calendar"</span>, <span class="token string">"token_type"</span><span class="token builtin class-name">:</span> <span class="token string">"Bearer"</span><span class="token punctuation">}</span></code></pre><h2 id="5-JS코드로-Access-Token-Refresh-Token으로-재발급까지-을-받아보자"><a href="#5-JS코드로-Access-Token-Refresh-Token으로-재발급까지-을-받아보자" class="headerlink" title="5. JS코드로 Access Token (+Refresh Token으로 재발급까지)을 받아보자"></a>5. JS코드로 Access Token (+Refresh Token으로 재발급까지)을 받아보자</h2><p>이러한 작업들을 일일이 하기에는 여러모로 피곤하니, 코드로 한 번 구현을 해봤다.</p><p>만약 이 코드를 돌렸는데 403 Forbidden이 나온다면 GCP에서 현재 사용하는 서비스의 API 사용을 허가했는지 확인해보자.<br>서비스 리스트는 <a href="https://console.cloud.google.com/apis/api">https://console.cloud.google.com/apis/api</a> 에서 확인할 수 있다.</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># .env.local</span><span class="token assign-left variable">GOOGLE_CLIENT_ID</span><span class="token operator">=</span><span class="token operator"><</span>클라이언트 ID<span class="token operator">></span><span class="token assign-left variable">GOOGLE_CLIENT_SECRET</span><span class="token operator">=</span><span class="token operator"><</span>클라이언트 보안 비밀번호<span class="token operator">></span><span class="token assign-left variable">GOOGLE_REDIRECT_URI</span><span class="token operator">=</span><span class="token operator"><</span>승인된 리디렉션 URI주소<span class="token operator">></span><span class="token assign-left variable">GOOGLE_REFRESH_TOKEN</span><span class="token operator">==</span><span class="token operator"><</span>refresh token값<span class="token operator">></span></code></pre><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// oauth.js</span><span class="token keyword">import</span> <span class="token punctuation">{</span> google <span class="token punctuation">}</span> <span class="token keyword">from</span> <span class="token string">'googleapis'</span><span class="token punctuation">;</span><span class="token keyword">async</span> <span class="token keyword">function</span> <span class="token function">getOAuth2Client</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> oAuth2Client <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">google<span class="token punctuation">.</span>auth<span class="token punctuation">.</span>OAuth2</span><span class="token punctuation">(</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">GOOGLE_CLIENT_ID</span><span class="token punctuation">,</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">GOOGLE_CLIENT_SECRET</span><span class="token punctuation">,</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">GOOGLE_REDIRECT_URI</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Refresh token 설정</span> oAuth2Client<span class="token punctuation">.</span><span class="token function">setCredentials</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">refresh_token</span><span class="token operator">:</span> process<span class="token punctuation">.</span>env<span class="token punctuation">.</span><span class="token constant">GOOGLE_REFRESH_TOKEN</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">try</span> <span class="token punctuation">{</span> <span class="token comment">// Access token 갱신</span> <span class="token keyword">const</span> <span class="token punctuation">{</span> token <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token keyword">await</span> oAuth2Client<span class="token punctuation">.</span><span class="token function">getAccessToken</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> oAuth2Client<span class="token punctuation">.</span><span class="token function">setCredentials</span><span class="token punctuation">(</span><span class="token punctuation">{</span> <span class="token literal-property property">access_token</span><span class="token operator">:</span> token <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> oAuth2Client<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span>e<span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">error</span><span class="token punctuation">(</span><span class="token string">'Failed to refresh access token:'</span><span class="token punctuation">,</span> e<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Error</span><span class="token punctuation">(</span><span class="token string">'Failed to get access token.'</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre>]]></content>
<categories>
<category> ☁️ Cloud </category>
</categories>
<tags>
<tag> OAuth2 </tag>
<tag> GCP </tag>
<tag> Cloud </tag>
</tags>
</entry>
<entry>
<title>[NCP] 콘솔에서 NKS(Ncloud Kubernetes Service) 및 NCR(Ncloud Container Registry) 세팅으로 배포하기</title>
<link href="/2024/11/25/Cloud/NCP/Console/NKS&NCR/"/>
<url>/2024/11/25/Cloud/NCP/Console/NKS&NCR/</url>
<content type="html"><![CDATA[<p>최근 멘토링에서 ncloud를 사용하여 서버배포를 하고싶다는 요청을 받았는데, 나 또한 네이버 클라우드는 경험이 없는지라 ㅎㅎ;; 공부삼아 한 번 세팅을 해봤다.</p><p>일단 클라우드에서 Kubernetes로 container를 배포를 하기 위해서는 로직이 대략적으로 이렇게 된다.<br><img src="./2.png" width="800"></p><ul><li>설명이 어렵다 할 분들을 위해서, 전체적인 로직은 Services 쪽을 보면 이해하기 쉬울 것이다.<br><code>Container Registry</code>에 컨테이너 이미지 업로드 -> <code>Ncloud Kubernetes Service</code>의 Kubernetes에 컨테이너 이미지 배치 -> Kubernetes가 서버를 배포하도록 설정<br>이렇게만 하면 클라우드에 우리가 원하는 이미지를 띄울 수 있다.</li><li>하지만 클라우드는 <code>보안</code>이 생명인 서비스인 만큼, 모든 것들이 기본적으로 private으로 설정되며 우리는 이런 리소스에 접근하기 위해서는 여러 인증을 n번 거쳐야한다. 때문에 VPC를 설정을 예쁘게 해야한다.<br>subnet 이름은 사람마다 취향껏 맞춰 지으면 되며, 여기서는 편의상 내 마음대로 이름을 붙여봤다.<ul><li><code>k8s-server-k2</code><ul><li>클러스터로 들어오는 내부 트래픽과 외부 트래픽을 관리</li><li>컨테이너 이미지를 레지스트리에서 가져와 클러스터에 배포</li><li>클러스터가 인터넷(외부 서비스)과 연결될 수 있도록 하는 Nat 관리</li></ul></li><li><code>k8s-lb-private</code>: 클러스터 내부에서만 접근할 수 있는 서비스들을 트래픽에 전달<ul><li>특히 내부 Pod간 통신 처리</li></ul></li><li><code>k8s-lb-public</code>: 인터넷을 통해 외부 사용자들이 접근할 수 있는 서비스들에 트래픽 전달<ul><li>특히 외부에서 트래픽을 받으면 pod로 라우팅함</li></ul></li><li><code>Nat</code>: NAT Gateway의 약자로, 외부에서 Kubernetes 클러스터 내부로의 직접적인 접근을 차단하기 위해 생성</li><li><code>k8s-k2</code>: Kubernetes 클러스터를 관리함. 쉽게 Kubernetes 클러스터의 worker nodes 관리하는 곳으로 생각하면 됨</li></ul></li></ul><p>이렇게 간략하게 설명을 해봤으며, 이해가 됐다면 바로 세팅으로 들어가보자.</p><h2 id="0-NCP-콘솔-로그인"><a href="#0-NCP-콘솔-로그인" class="headerlink" title="0. NCP 콘솔 로그인"></a>0. NCP 콘솔 로그인</h2><img src="./0.png" width="800"><p>화면 맨 위 오른쪽에 <a href="https://console.ncloud.com/dashboard">콘솔</a> 버튼을 누르면 접속할 수 있다.</p><h2 id="1-VPC-생성하기"><a href="#1-VPC-생성하기" class="headerlink" title="1. VPC 생성하기"></a>1. VPC 생성하기</h2><ul><li>VPC > <a href="https://console.ncloud.com/vpc-network/vpc">VPC Management</a>에서 생성</li></ul><img src="./1.png" width="800"><h2 id="2-Subnet-생성하기"><a href="#2-Subnet-생성하기" class="headerlink" title="2. Subnet 생성하기"></a>2. Subnet 생성하기</h2><ul><li>VPC > <a href="https://console.ncloud.com/vpc-network/subnet">Subnet Management</a>에서 생성</li><li>1번에서 생성한 VPC 이름으로 설정</li></ul><img src="./3.png" width="800"><h2 id="3-NAT-Gateway-생성하기"><a href="#3-NAT-Gateway-생성하기" class="headerlink" title="3. NAT Gateway 생성하기"></a>3. NAT Gateway 생성하기</h2><ul><li>VPC > <a href="https://console.ncloud.com/vpc-network/nat-gateway">NAT Gateway</a>에서 생성</li><li>1, 2번에서 생성한 VPC 및 nat subnet 설정</li></ul><img src="./4.png" width="800"><h2 id="4-Routes-설정하기"><a href="#4-Routes-설정하기" class="headerlink" title="4. Routes 설정하기"></a>4. Routes 설정하기</h2><ul><li>VPC > Route Table > <a href="https://console.ncloud.com/vpc-network/routeTable">Route Table</a>에서 <code>private-table</code> 선택</li><li><code>Route 설정</code>에서 public access를 위해 <code>0.0.0.0/0</code>, <code>NATGW</code>, <code>nat설정의 subnet 이름</code> 추가</li></ul><img src="./5.png" width="800"><h2 id="5-Object-Storage-생성하기"><a href="#5-Object-Storage-생성하기" class="headerlink" title="5. Object Storage 생성하기"></a>5. Object Storage 생성하기</h2><ul><li>Object Storage > <a href="https://console.ncloud.com/objectStorage/objectStorageList">Bucket Management</a>에서 버킷 생성</li></ul><img src="./6.png" width="300"><h2 id="6-Container-Registry-생성하기"><a href="#6-Container-Registry-생성하기" class="headerlink" title="6. Container Registry 생성하기"></a>6. Container Registry 생성하기</h2><ul><li><a href="https://console.ncloud.com/ncr/registries">Container Registry</a>에서 생성</li><li>5번에서 생성한 버킷으로 설정</li></ul><img src="./7.png" width="800"><h2 id="7-Ncloud-Kubernetes-Service-생성하기"><a href="#7-Ncloud-Kubernetes-Service-생성하기" class="headerlink" title="7. Ncloud Kubernetes Service 생성하기"></a>7. Ncloud Kubernetes Service 생성하기</h2><h3 id="1-VPC-Ncloud-Kubernetes-Service-Clusters에서-생성"><a href="#1-VPC-Ncloud-Kubernetes-Service-Clusters에서-생성" class="headerlink" title="1) VPC Ncloud Kubernetes Service Clusters에서 생성"></a>1) <a href="https://console.ncloud.com/vnks/clusters">VPC Ncloud Kubernetes Service Clusters</a>에서 생성</h3><ul><li><p>1번에서 생성한 VPC를 선택하면 자동으로 LB Private subnet, LB Public subnet이 세팅됨</p></li><li><p>이번 실습에서는 클러스터 인증 모드를 API로 설정함<br><img src="./9.png" width="800"></p></li><li><p>설정 완료 후 다음으로 넘어가면 Nat 설정에 관한 안내창이 나오는데, 무시해도 됨(이 세팅은 3번, 5번에서 했기 때문)</p><img src="./8.png" width="400"></li></ul><h3 id="2-노드풀-설정하기"><a href="#2-노드풀-설정하기" class="headerlink" title="2) 노드풀 설정하기"></a>2) 노드풀 설정하기</h3> <img src="./10.png" width="800"><h3 id="3-인증키-설정"><a href="#3-인증키-설정" class="headerlink" title="3) 인증키 설정"></a>3) 인증키 설정</h3> <img src="./11.png" width="800"><p><br><br></p><p>모든 설정이 완료되면 아래 이미지처럼 생성됨.약 10-30분 기다려야함<br><img src="./12.png" width="800"></p><h2 id="8-사용자-인증-API-인증키-생성하기"><a href="#8-사용자-인증-API-인증키-생성하기" class="headerlink" title="8. 사용자 인증: API 인증키 생성하기"></a>8. 사용자 인증: API 인증키 생성하기</h2><ul><li>계정 관리 > <a href="https://www.ncloud.com/mypage/manage/authkey">인증키 관리</a>에서 <code>신규 API 인증키 생성</code>을 클릭하여 API 인증키 생성하기</li><li><code>Access Key ID</code> 및 <code>Secret Key</code> 값을 준비해두자. 앞으로 서비스 이용을 할 때 쓸 예정</li></ul><h2 id="9-Container-Registry에-Docker-image-업로드하기"><a href="#9-Container-Registry에-Docker-image-업로드하기" class="headerlink" title="9. Container Registry에 Docker image 업로드하기"></a>9. Container Registry에 Docker image 업로드하기</h2><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># ncloud docker login 하기</span><span class="token comment"># registry-url = container registry의 public endpoint</span>$ <span class="token function">docker</span> login <span class="token operator"><</span>registry-url<span class="token operator">></span><span class="token comment"># docker build & tag & push 하기</span><span class="token comment"># docker build: ncloud의 Kubernetes 세팅이 amd64으로 되어있어 platform 옵션 추가</span>$ <span class="token function">docker</span> build <span class="token parameter variable">--platform</span> linux/amd64 <span class="token parameter variable">-t</span> <span class="token operator"><</span>registry-url<span class="token operator">></span>/<span class="token operator"><</span>repository-name<span class="token operator">></span>:<span class="token operator"><</span>tag<span class="token operator">></span> <span class="token builtin class-name">.</span>$ <span class="token function">docker</span> tag $ <span class="token function">docker</span> push <span class="token operator"><</span>registry-url<span class="token operator">></span>/<span class="token operator"><</span>repository-name<span class="token operator">></span>:<span class="token operator"><</span>tag<span class="token operator">></span></code></pre><img src="./15.png" width="800">Push가 잘됐다면 이미지처럼 Tags탭에 들어갔을 때 push한 이미지를 확인할 수 있다.<h2 id="10-Kubernetes-설정해서-Docker-image-배포하기"><a href="#10-Kubernetes-설정해서-Docker-image-배포하기" class="headerlink" title="10. Kubernetes 설정해서 Docker image 배포하기"></a>10. Kubernetes 설정해서 Docker image 배포하기</h2><h3 id="NKS-인증키-설정"><a href="#NKS-인증키-설정" class="headerlink" title="NKS 인증키 설정"></a>NKS 인증키 설정</h3><p><a href="https://guide.ncloud-docs.com/docs/k8s-iam-auth-ncp-iam-authenticator">여기</a>를 참고하여 ncp-iam-authenticator를 설치한 후 진행</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># ncloud setup</span>$ <span class="token builtin class-name">export</span> <span class="token assign-left variable">NCLOUD_ACCESS_KEY</span><span class="token operator">=</span><span class="token operator"><</span><span class="token number">8</span>번에서-생성한-Access-Key-ID<span class="token operator">></span>$ <span class="token builtin class-name">export</span> <span class="token assign-left variable">NCLOUD_SECRET_KEY</span><span class="token operator">=</span><span class="token operator"><</span><span class="token number">8</span>번에서-생성한-Secret-Key<span class="token operator">></span>$ <span class="token builtin class-name">export</span> <span class="token assign-left variable">NCLOUD_API_GW</span><span class="token operator">=</span>https://ncloud.apigw.ntruss.com<span class="token comment"># nks 인증키 생성</span><span class="token comment"># region이 한국이면 region-code는 KR</span><span class="token comment"># 파일이 생성되지 않거나, 빈 파일이 생성됐다면 문제가 있는 것</span>$ ncp-iam-authenticator create-kubeconfig <span class="token parameter variable">--region</span> <span class="token operator"><</span>region-code<span class="token operator">></span> <span class="token parameter variable">--clusterUuid</span> <span class="token operator"><</span>NKS에서 생성한 cluster의 uuid<span class="token operator">></span> <span class="token parameter variable">--output</span> kubeconfig.yaml$ <span class="token builtin class-name">export</span> <span class="token assign-left variable">KUBECONFIG</span><span class="token operator">=</span><span class="token string">"<kubeconfig.yaml의 파일 절대경로>"</span><span class="token comment"># Kubernetes가 제대로 설정됐는지 확인</span>$ kubectl get ns <span class="token comment"># namespace 조회. 아래같이 나오면 성공</span>NAME STATUS AGEdefault Active 40hkube-node-lease Active 40hkube-public Active 40hkube-system Active 40h</code></pre><h3 id="Kubernetes를-위한-yaml파일-생성"><a href="#Kubernetes를-위한-yaml파일-생성" class="headerlink" title="Kubernetes를 위한 yaml파일 생성"></a>Kubernetes를 위한 yaml파일 생성</h3><pre class="language-yaml" data-language="yaml"><code class="language-yaml"><span class="token comment"># deployment.yaml</span><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> apps/v1<span class="token key atrule">kind</span><span class="token punctuation">:</span> Deployment<span class="token key atrule">metadata</span><span class="token punctuation">:</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> my<span class="token punctuation">-</span>app<span class="token punctuation">-</span>deployment <span class="token key atrule">namespace</span><span class="token punctuation">:</span> default<span class="token key atrule">spec</span><span class="token punctuation">:</span> <span class="token key atrule">replicas</span><span class="token punctuation">:</span> <span class="token number">1</span> <span class="token key atrule">selector</span><span class="token punctuation">:</span> <span class="token key atrule">matchLabels</span><span class="token punctuation">:</span> <span class="token key atrule">app</span><span class="token punctuation">:</span> my<span class="token punctuation">-</span>app <span class="token key atrule">template</span><span class="token punctuation">:</span> <span class="token key atrule">metadata</span><span class="token punctuation">:</span> <span class="token key atrule">labels</span><span class="token punctuation">:</span> <span class="token key atrule">app</span><span class="token punctuation">:</span> my<span class="token punctuation">-</span>app <span class="token key atrule">spec</span><span class="token punctuation">:</span> <span class="token key atrule">containers</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> my<span class="token punctuation">-</span>app <span class="token key atrule">image</span><span class="token punctuation">:</span> <registry<span class="token punctuation">-</span>url<span class="token punctuation">></span>/<repository<span class="token punctuation">-</span>name<span class="token punctuation">></span><span class="token punctuation">:</span><tag<span class="token punctuation">></span> <span class="token key atrule">imagePullPolicy</span><span class="token punctuation">:</span> Always <span class="token key atrule">ports</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">containerPort</span><span class="token punctuation">:</span> <span class="token number">8000</span> <span class="token key atrule">imagePullSecrets</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> regcred</code></pre><pre class="language-yaml" data-language="yaml"><code class="language-yaml"><span class="token comment"># service.yaml</span><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> v1<span class="token key atrule">kind</span><span class="token punctuation">:</span> Service<span class="token key atrule">metadata</span><span class="token punctuation">:</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> my<span class="token punctuation">-</span>app<span class="token punctuation">-</span>service <span class="token key atrule">annotations</span><span class="token punctuation">:</span> <span class="token key atrule">service.beta.Kubernetes.io/ncloud-load-balancer-layer-type</span><span class="token punctuation">:</span> <span class="token string">"nplb"</span> <span class="token key atrule">service.beta.Kubernetes.io/ncloud-load-balancer-size</span><span class="token punctuation">:</span> <span class="token string">"SMALL"</span><span class="token key atrule">spec</span><span class="token punctuation">:</span> <span class="token key atrule">selector</span><span class="token punctuation">:</span> <span class="token key atrule">app</span><span class="token punctuation">:</span> my<span class="token punctuation">-</span>app <span class="token key atrule">type</span><span class="token punctuation">:</span> LoadBalancer <span class="token key atrule">ports</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">port</span><span class="token punctuation">:</span> <span class="token number">80</span> <span class="token key atrule">targetPort</span><span class="token punctuation">:</span> <span class="token number">8000</span></code></pre><h3 id="Kubernetes에-템플릿-배포-및-서비스-확인"><a href="#Kubernetes에-템플릿-배포-및-서비스-확인" class="headerlink" title="Kubernetes에 템플릿 배포 및 서비스 확인"></a>Kubernetes에 템플릿 배포 및 서비스 확인</h3><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># kubenetes secret object 생성</span>$ kubectl create secret docker-registry regcred <span class="token punctuation">\</span> --docker-server<span class="token operator">=</span><span class="token operator"><</span>registry-url<span class="token operator">></span> <span class="token punctuation">\</span> --docker-username<span class="token operator">=</span><span class="token operator"><</span><span class="token number">8</span>번에서-생성한-Access-Key-ID<span class="token operator">></span> <span class="token punctuation">\</span> --docker-password<span class="token operator">=</span><span class="token operator"><</span><span class="token number">8</span>번에서-생성한-Secret-Key<span class="token operator">></span> <span class="token punctuation">\</span> --docker-email<span class="token operator">=</span><span class="token operator"><</span>ncloud-email-주소<span class="token operator">></span>$ kubectl get secrets <span class="token comment"># 생성이 잘 됐는지 확인하는 명령어</span><span class="token comment"># yaml 템플릿 업로드</span>$ kubectl apply <span class="token parameter variable">-f</span> deployment.yaml$ kubectl apply <span class="token parameter variable">-f</span> service.yaml$ kubectl get pods <span class="token comment"># status running인지 확인하는 명령어</span><span class="token comment"># 클라우드에 배포된 IP주소 확인하기</span><span class="token comment"># LoadBalancer의 External IP 주소 = 곧 클라우드에 배포된 서비스 IP 주소</span>$ kubectl get servicesNAME TYPE CLUSTER-IP EXTERNAL-IP PORT<span class="token punctuation">(</span>S<span class="token punctuation">)</span> AGEKubernetes ClusterIP <span class="token number">198.19</span>.128.1 <span class="token operator"><</span>none<span class="token operator">></span> <span class="token number">443</span>/TCP 40hmy-app-service LoadBalancer <span class="token number">198.19</span>.255.184 default-my-app-service-cfe50-100590090-dcc6483894d3.kr.lb.naverncp.com <span class="token number">80</span>:30167/TCP 39h</code></pre><h2 id="11-배포-페이지-접근해보기"><a href="#11-배포-페이지-접근해보기" class="headerlink" title="11. 배포 페이지 접근해보기"></a>11. 배포 페이지 접근해보기</h2><p>글 업로드 시점 기준으로 서비스 중단해서 접속 안됩니다. 참고하세용<br><img src="./16.png" width="800"></p><h2 id="12-만약-Docker-이미지를-업데이트를-해서-서버에-반영하고-싶다면"><a href="#12-만약-Docker-이미지를-업데이트를-해서-서버에-반영하고-싶다면" class="headerlink" title="12. 만약 Docker 이미지를 업데이트를 해서 서버에 반영하고 싶다면?"></a>12. 만약 Docker 이미지를 업데이트를 해서 서버에 반영하고 싶다면?</h2><p>Kubernetes의 deployment.yaml에 이미 <code>imagePullPolicy</code> 세팅이 <code>Always</code>로 되어있어서 같은 태그를 push했을 때는 자동으로 Kubernetes가 이미지를 추적하여 업데이트를 할 것이다.<br>다만 사람마다 태그 규칙이 다르며, 이 때문에 tag 버전이 업데이트 된 이미지를 업로드를 한다면 Kubernetes가 알아차리지 못하니 우리가 알려줘야 한다.</p><p>다음은 kubernets에게 새로운 container image가 생겼다는 것을 알려주는 작업이다.</p><ol><li><code>deployment.yaml</code> 수정</li></ol><pre class="language-yaml" data-language="yaml"><code class="language-yaml"><span class="token comment"># deployment.yaml</span><span class="token key atrule">apiVersion</span><span class="token punctuation">:</span> apps/v1<span class="token key atrule">kind</span><span class="token punctuation">:</span> Deployment<span class="token key atrule">metadata</span><span class="token punctuation">:</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> my<span class="token punctuation">-</span>app<span class="token punctuation">-</span>deployment <span class="token key atrule">namespace</span><span class="token punctuation">:</span> default<span class="token key atrule">spec</span><span class="token punctuation">:</span> <span class="token punctuation">...</span> <span class="token key atrule">spec</span><span class="token punctuation">:</span> <span class="token key atrule">containers</span><span class="token punctuation">:</span> <span class="token punctuation">-</span> <span class="token key atrule">name</span><span class="token punctuation">:</span> my<span class="token punctuation">-</span>app <span class="token key atrule">image</span><span class="token punctuation">:</span> <registry<span class="token punctuation">-</span>url<span class="token punctuation">></span>/<repository<span class="token punctuation">-</span>name<span class="token punctuation">></span><span class="token punctuation">:</span><tag<span class="token punctuation">></span> <span class="token comment"># tag에 맞춰 수정</span><span class="token punctuation">...</span></code></pre><ol start="2"><li>deployment 서비스 재시작</li></ol><pre class="language-bash" data-language="bash"><code class="language-bash">kubectl rollout restart deployment <span class="token operator"><</span>deployment.yaml의 metadata.name<span class="token operator">></span></code></pre>]]></content>
<categories>
<category> ☁️ Cloud </category>
</categories>
<tags>
<tag> Container </tag>
<tag> Docker </tag>
<tag> Network </tag>
<tag> Cloud </tag>
<tag> NCP </tag>
<tag> VPC </tag>
<tag> Kubernetes </tag>
</tags>
</entry>
<entry>
<title>[TIPS] Mermaid 명령어로 Diagram 그리기</title>
<link href="/2024/11/23/Tips/Tool/"/>
<url>/2024/11/23/Tips/Tool/</url>
<content type="html"><![CDATA[<p>프로젝트를 하다보면 flow chart나 diagram을 그려야 하는데, 이게 여간 귀찮은 일이 아닐 수 없다.<br>빠르고 간단하게 그리고 싶은 분들은 Mermaid 명령어로 그려보는걸 추천한다.</p><h2 id="Mermaid"><a href="#Mermaid" class="headerlink" title="Mermaid"></a><a href="https://mermaid.js.org/">Mermaid</a></h2><img src="./3.png" width="150"><p>Markdown(마크다운) 명령어로 diagram을 그릴 수 있는 툴이다.<br>압도적인 점유율을 자랑하는 우리의 Github에서는 이 문법을 지원하기 때문에, README.md파일 같은 곳에서 작성해두면 내용을 시각하하여 볼 수 있는 장점이 있다.</p><h2 id="Mermaid-ChatGPT로-간단하게-만들기"><a href="#Mermaid-ChatGPT로-간단하게-만들기" class="headerlink" title="Mermaid + ChatGPT로 간단하게 만들기"></a>Mermaid + ChatGPT로 간단하게 만들기</h2><p>사용법을 공부해서 적용하면 되지만 아무래도 어떤 관계인지 정리를 해야하니 머리가 여간 복잡할 수 밖에 없다…<br>따라서 21세기 최고의 도구인 AI를 이용해보도록 하자.</p><ol><li><a href="https://chatgpt.com/">ChatGPT</a>에 어떤 그림을 그릴지 설명한다. 이 때 mermaid 문법으로 써달라고 요청하면 예쁘게 뽑아준다. ctrl+c를 해준다.</li></ol><img src="./1.png" width="600"><ol start="2"><li><a href="https://mermaid.live/edit">Mermaid Live Editor</a>에 접속해서 ctrl+v를 해준다.</li></ol><img src="./2.png" width="600">]]></content>
<categories>
<category> 💾 Etc </category>
</categories>
<tags>
<tag> Diagram </tag>
</tags>
</entry>
<entry>
<title>Docker 정리</title>
<link href="/2024/11/11/DevOps/Docker/"/>
<url>/2024/11/11/DevOps/Docker/</url>
<content type="html"><![CDATA[<p>이 글을 읽는 사람은 먼저 <a href="/2024/07/12/DevOps/Container/" title="Container 정리">Container 정리</a>부터 정리하고 읽는 것을 추천한다.</p><p>Docker는 컨테이너 기반의 애플리케이션 개발, 배포, 실행을 자동화하는 오픈소스로 대부분의 기업들에서 컨테이너 관련 기술로 채택하는 기술이다.</p><h2 id="1-Docker-개념"><a href="#1-Docker-개념" class="headerlink" title="1. Docker 개념"></a>1. Docker 개념</h2><h3 id="Docker-Image"><a href="#Docker-Image" class="headerlink" title="Docker Image"></a>Docker Image</h3><ul><li>컨테이너를 실행하기 위한 읽기 전용 템플릿</li><li>애플리케이션과 실행 환경 (라이브러리, 의존성) 포함</li><li>이미지 빌드를 위해서는 <code>Dockerfile</code> 스크립트 파일이 필요: 단계별로 애플리케이션 설치 및 환경 설정 정의</li></ul><h3 id="Docker-Container"><a href="#Docker-Container" class="headerlink" title="Docker Container"></a>Docker Container</h3><ul><li>이미지에서 생성된 실행 가능한 인스턴스</li><li>애플리케이션과 환경이 실행되는 독립적인 단위</li></ul><h3 id="Docker-Registry"><a href="#Docker-Registry" class="headerlink" title="Docker Registry"></a>Docker Registry</h3><ul><li>이미지 저장소 (ex. Docker Hub, AWS ECR, GCP Container Registry 등 포함)</li></ul><h2 id="2-Docker-명령어-정리"><a href="#2-Docker-명령어-정리" class="headerlink" title="2. Docker 명령어 정리"></a>2. Docker 명령어 정리</h2><h3 id="1-Docker-설치-확인"><a href="#1-Docker-설치-확인" class="headerlink" title="1) Docker 설치 확인"></a>1) Docker 설치 확인</h3><ul><li>version 확인: <code>docker --version</code><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> <span class="token parameter variable">--version</span>Docker version <span class="token number">20.10</span>.23, build <span class="token number">7155243</span></code></pre></li></ul><br><ul><li>info 확인: <code>docker info</code><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> infoClient: Context: default Debug Mode: <span class="token boolean">false</span> Plugins: buildx: Docker Buildx <span class="token punctuation">(</span>Docker Inc., v0.10.3<span class="token punctuation">)</span> compose: Docker Compose <span class="token punctuation">(</span>Docker Inc., v2.15.1<span class="token punctuation">)</span> dev: Docker Dev Environments <span class="token punctuation">(</span>Docker Inc., v0.1.0<span class="token punctuation">)</span> extension: Manages Docker extensions <span class="token punctuation">(</span>Docker Inc., v0.2.18<span class="token punctuation">)</span> sbom: View the packaged-based Software Bill Of Materials <span class="token punctuation">(</span>SBOM<span class="token punctuation">)</span> <span class="token keyword">for</span> an image <span class="token punctuation">(</span>Anchore Inc., <span class="token number">0.6</span>.0<span class="token punctuation">)</span> scan: Docker Scan <span class="token punctuation">(</span>Docker Inc., v0.25.0<span class="token punctuation">)</span> scout: Command line tool <span class="token keyword">for</span> Docker Scout <span class="token punctuation">(</span>Docker Inc., v0.6.0<span class="token punctuation">)</span>Server: Containers: <span class="token number">4</span> Running: <span class="token number">0</span> Paused: <span class="token number">0</span> Stopped: <span class="token number">4</span> Images: <span class="token number">14</span> Server Version: <span class="token number">20.10</span>.23 Storage Driver: overlay2 Backing Filesystem: extfs Supports d_type: <span class="token boolean">true</span> Native Overlay Diff: <span class="token boolean">true</span> userxattr: <span class="token boolean">false</span> Logging Driver: json-file Cgroup Driver: cgroupfs Cgroup Version: <span class="token number">2</span> Plugins: Volume: <span class="token builtin class-name">local</span> Network: bridge <span class="token function">host</span> ipvlan macvlan null overlay Log: awslogs fluentd gcplogs gelf journald json-file <span class="token builtin class-name">local</span> logentries splunk syslog Swarm: inactive Runtimes: io.containerd.runc.v2 io.containerd.runtime.v1.linux runc Default Runtime: runc Init Binary: docker-init containerd version: 2456e983eb9e37e47538f59ea18f2043c9a73640 runc version: v1.1.4-0-g5fd4c4d init version: de40ad0 Security Options: seccomp Profile: default cgroupns Kernel Version: <span class="token number">5.15</span>.49-linuxkit Operating System: Docker Desktop OSType: linux Architecture: aarch64 CPUs: <span class="token number">4</span> Total Memory: <span class="token number">7</span>.668GiB Name: docker-desktop ID: 276G:OJLG:WHVN:JV37:CX4G:VAC2:K2AY:TJPC:M2RA:D5NR:DWTP:HU2G Docker Root Dir: /var/lib/docker Debug Mode: <span class="token boolean">false</span> HTTP Proxy: http.docker.internal:3128 HTTPS Proxy: http.docker.internal:3128 No Proxy: hubproxy.docker.internal Registry: https://index.docker.io/v1/ Labels: Experimental: <span class="token boolean">false</span> Insecure Registries: hubproxy.docker.internal:5000 <span class="token number">127.0</span>.0.0/8 Live Restore Enabled: <span class="token boolean">false</span></code></pre></li></ul><h3 id="2-Docker-이미지-관리"><a href="#2-Docker-이미지-관리" class="headerlink" title="2) Docker 이미지 관리"></a>2) Docker 이미지 관리</h3><ul><li>Docker Hub에서 이미지 검색: <code>docker search <이미지명></code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> search <span class="token builtin class-name">test</span>NAME DESCRIPTION STARS OFFICIAL AUTOMATEDimmcantation/test Immcantation unit <span class="token builtin class-name">test</span> image <span class="token number">1</span>pachyderm/test <span class="token number">0</span>islandora/test This image is exclusively used <span class="token keyword">for</span> manually … <span class="token number">0</span>okteto/test <span class="token number">0</span>amir20/test <span class="token number">0</span>kubeovn/test <span class="token number">0</span>voxpupuli/test Container repo to <span class="token builtin class-name">test</span> container build and V… <span class="token number">0</span>corpusops/test <span class="token number">0</span>ratelimitpreview/test <span class="token number">0</span>test/testimage20130921141042 <span class="token number">0</span>test/testimage20130919235830 <span class="token number">0</span>test/testimage20130921221004 <span class="token number">0</span>test/testimage20130919223925 <span class="token number">0</span>test/testimage20130921190956 <span class="token number">0</span>test/testimage20130922032014 <span class="token number">0</span>doct15/test <span class="token number">0</span>flypenguin/test A <span class="token builtin class-name">test</span> container <span class="token keyword">for</span> <span class="token punctuation">..</span>. k8s <span class="token builtin class-name">:</span><span class="token punctuation">)</span> <span class="token number">0</span> <span class="token punctuation">[</span>OK<span class="token punctuation">]</span>brimworks/test <span class="token number">0</span>flvranckx/test <span class="token builtin class-name">test</span> <span class="token number">0</span>chiphwang/test <span class="token number">0</span>divyag2411/test <span class="token number">0</span>realmaccess/test <span class="token number">0</span>devopsatburst/test <span class="token number">0</span>hopar/test <span class="token builtin class-name">test</span> descr <span class="token number">0</span>femycatherine/test <span class="token builtin class-name">test</span> <span class="token number">0</span></code></pre><br><ul><li>특정 이미지를 로컬로 다운로드: <code>docker pull <이미지명>:<태그></code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> pull nginx:latestlatest: Pulling from library/nginxDigest: sha256:bc5eac5eafc581aeda3008b4b1f07ebba230de2f27d47767129a6a905c84f470Status: Image is up to <span class="token function">date</span> <span class="token keyword">for</span> nginx:latestdocker.io/library/nginx:latest</code></pre><br><ul><li>로컬에 저장된 이미지 나열: <code>docker images</code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> imagesREPOSITORY TAG IMAGE ID CREATED SIZEdjango-app latest cbb6dff7c55a <span class="token number">2</span> days ago <span class="token number">2</span>.12GBpostgres <span class="token number">15</span>-alpine c558f49f952d <span class="token number">3</span> days ago 256MBpython <span class="token number">3.12</span>-slim e359a8be29f6 <span class="token number">5</span> weeks ago 150MBredis alpine 4a6fa001a1b0 <span class="token number">7</span> weeks ago <span class="token number">48</span>.3MBnginx latest 7a3f95c07812 <span class="token number">7</span> weeks ago 197MB</code></pre><br><ul><li>로컬에 저장된 이미지 삭제: `docker rmi <이미지ID></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> imagesREPOSITORY TAG IMAGE ID CREATED SIZEpython latest 62639b6c3f3e <span class="token number">5</span> weeks ago <span class="token number">1</span>.02GB$ <span class="token function">docker</span> rmi <span class="token number">626</span> <span class="token comment"># 전부 다 안써도 특정 이미지인지 인지할 수 있으면 됨</span>Untagged: python:latestUntagged: python@sha256:bc78d3c007f86dbb87d711b8b082d9d564b8025487e780d24ccb8581d83ef8b0Deleted: sha256:62639b6c3f3e77ebbbf3f18802d08351636f8dd6e0a94d1b225e9f5dc1c88044Deleted: sha256:476e07a0f38bafed4e474712d0e3d37dbcb7ff90d06e17bb8d1fc4b2f14e7d35Deleted: sha256:2c190c9407be9104a7d2b741a4d91364bf2be04b81784dddaf13c9f188562e4dDeleted: sha256:e00fefe3633c24a34f09149c5f3dbc2330630a365ffedff052f988c3585a1ee2Deleted: sha256:c6d7f5d3800ca99cabcb02e8b21872f3a09cebe3973f5c98ebb3840435e0fd0fDeleted: sha256:d4a8223e1c6c5461929b8b25b9bdb78d194803d9ca62f94f43df43d8e4b17e47Deleted: sha256:a354dc33fe33b2600cf4fb75dd3ad14d4e0eecb77da53b75d7aefa7487e3bd17Deleted: sha256:ec8ae7dad7aba50e0f8bff1dc969d34d3584fb7ada6ce9948dad83e95939b5cc</code></pre><h3 id="3-Docker-컨테이너-관리"><a href="#3-Docker-컨테이너-관리" class="headerlink" title="3) Docker 컨테이너 관리"></a>3) Docker 컨테이너 관리</h3><ul><li>컨테이너 실행: <code>docker run <컨테이너명> -p <호스트포트>:<컨테이너포트> <이미지명> <option: 컨테이너 내부 명령어></code><ul><li><code>-d</code>: 백그라운드 실행</li><li><code>--name <컨테이너명></code>: 컨테이너 이름 설정</li><li><code>-p <호스트포트>:<컨테이너포트></code>: 포트 매핑</li><li><code>-e <변수=값></code>: 환경변수</li></ul></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> imagesREPOSITORY TAG IMAGE ID CREATED SIZEpython latest 62639b6c3f3e <span class="token number">5</span> weeks ago <span class="token number">1</span>.02GBpython <span class="token number">3.12</span>-slim e359a8be29f6 <span class="token number">5</span> weeks ago 150MB<span class="token comment"># my-python이라는 컨테이너명으로</span><span class="token comment"># 컨테이너 포트가 56인걸 호스트포트 1234로 연결</span><span class="token comment"># 이미지명은 python이며, 백그라운드에서 실행</span>$ <span class="token function">docker</span> run <span class="token parameter variable">-d</span> <span class="token parameter variable">--name</span> my-python <span class="token parameter variable">-p</span> <span class="token number">1234</span>:56 pythonb7711eb537add805b8628277d4c677dd3d91e009d3b64bbac81e60fa84f53928<span class="token comment"># 환경변수가 Foo를 설정하고 값을 bar로 설정</span><span class="token comment"># 컨테이너 실행 이미지는 python:3.12-slim</span><span class="token comment"># 컨테이너 내부 실행 명령어는 env (컨테이너 내부의 모든 환경변수 출력하는 unix 명령어)</span>$ <span class="token function">docker</span> run <span class="token parameter variable">-e</span> <span class="token assign-left variable">FOO</span><span class="token operator">=</span>bar python:3.12-slim <span class="token function">env</span><span class="token assign-left variable"><span class="token environment constant">PATH</span></span><span class="token operator">=</span>/usr/local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin<span class="token assign-left variable"><span class="token environment constant">HOSTNAME</span></span><span class="token operator">=</span>b20562c470be<span class="token assign-left variable">FOO</span><span class="token operator">=</span>bar<span class="token assign-left variable"><span class="token environment constant">LANG</span></span><span class="token operator">=</span>C.UTF-8<span class="token assign-left variable">GPG_KEY</span><span class="token operator">=</span>7169605F62C751356D054A26A821E680E5FA6305<span class="token assign-left variable">PYTHON_VERSION</span><span class="token operator">=</span><span class="token number">3.12</span>.7<span class="token assign-left variable">PYTHON_SHA256</span><span class="token operator">=</span>24887b92e2afd4a2ac602419ad4b596372f67ac9b077190f459aba390faf5550<span class="token assign-left variable"><span class="token environment constant">HOME</span></span><span class="token operator">=</span>/root</code></pre><br><ul><li>실행 중인 컨테이너 확인: <code>docker ps</code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> imagesREPOSITORY TAG IMAGE ID CREATED SIZEdjango-app latest cbb6dff7c55a <span class="token number">2</span> days ago <span class="token number">2</span>.12GB$ <span class="token function">docker</span> run <span class="token parameter variable">-d</span> django-app:latest275bdef89cc40711dad78833d7b5aeb27f75b4e423bea1279564a99dece45178$ <span class="token function">docker</span> <span class="token function">ps</span>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES275bdef89cc4 django-app:latest <span class="token string">"/bin/bash -c 'sourc…"</span> <span class="token number">3</span> seconds ago Up <span class="token number">2</span> seconds <span class="token number">8000</span>/tcp relaxed_euclid</code></pre><br><ul><li>모든 컨테이너 확인 (중단된 컨테이너 포함): <code>docker ps -a</code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> <span class="token function">ps</span> <span class="token parameter variable">-a</span>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES275bdef89cc4 django-app:latest <span class="token string">"/bin/bash -c 'sourc…"</span> About a minute ago Up About a minute <span class="token number">8000</span>/tcp relaxed_euclidf6d665ae418b python:3.12-slim <span class="token string">"python3"</span> <span class="token number">2</span> minutes ago Exited <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token number">2</span> minutes ago intelligent_easley7c72d2379677 python:3.12-slim <span class="token string">"-d"</span> <span class="token number">2</span> minutes ago</code></pre><ul><li>컨테이너 내부 접속: `docker exec -it <컨테이너ID> /bin/bash</li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> <span class="token function">ps</span>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES275bdef89cc4 django-app:latest <span class="token string">"/bin/bash -c 'sourc…"</span> <span class="token number">7</span> minutes ago Up <span class="token number">7</span> minutes <span class="token number">8000</span>/tcp relaxed_euclid$ <span class="token function">docker</span> <span class="token builtin class-name">exec</span> <span class="token parameter variable">-it</span> 275bdef89cc4 /bin/bash$ root@275bdef89cc4:/app<span class="token comment">#</span></code></pre><br><ul><li>실행 중인 컨테이너 중지: <code>docker stop <컨테이너ID></code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> <span class="token function">ps</span>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES275bdef89cc4 django-app:latest <span class="token string">"/bin/bash -c 'sourc…"</span> <span class="token number">8</span> minutes ago Up <span class="token number">8</span> minutes <span class="token number">8000</span>/tcp relaxed_euclid$ <span class="token function">docker</span> stop 275bdef89cc4275bdef89cc4$ <span class="token function">docker</span> <span class="token function">ps</span>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES$</code></pre><br><ul><li>중단된 컨테이너 시작: <code>docker start <컨테이너ID></code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> <span class="token function">ps</span> <span class="token comment"># 실행 중인 컨테이너 없음</span>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES$ <span class="token function">docker</span> <span class="token function">ps</span> <span class="token parameter variable">-a</span> <span class="token comment"># 중단된 컨테이너를 확인해봄</span>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES275bdef89cc4 django-app:latest <span class="token string">"/bin/bash -c 'sourc…"</span> <span class="token number">10</span> minutes ago Exited <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token number">2</span> minutes ago relaxed_euclid$ <span class="token function">docker</span> start 275bdef89cc4 <span class="token comment"># 최근에 중단된거 재시작</span>275bdef89cc4$ <span class="token variable">$docker</span> <span class="token function">ps</span>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES275bdef89cc4 django-app:latest <span class="token string">"/bin/bash -c 'sourc…"</span> <span class="token number">11</span> minutes ago Up <span class="token number">3</span> seconds <span class="token number">8000</span>/tcp relaxed_euclid</code></pre><br><ul><li>중단된 컨테이너 삭제: <code>docker rm <컨테이너ID></code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> <span class="token function">ps</span> <span class="token parameter variable">-a</span>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES275bdef89cc4 django-app:latest <span class="token string">"/bin/bash -c 'sourc…"</span> <span class="token number">15</span> minutes ago Exited <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token number">4</span> minutes ago relaxed_euclidf6d665ae418b python:3.12-slim <span class="token string">"python3"</span> <span class="token number">17</span> minutes ago Exited <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token number">17</span> minutes ago intelligent_easley7c72d2379677 python:3.12-slim <span class="token string">"-d"</span> <span class="token number">17</span> minutes ago Created adoring_jang$ <span class="token function">docker</span> <span class="token function">rm</span> <span class="token number">27</span> <span class="token comment"># ID를 전부 다 쓰지 않아도, 해당 이미지를 찾을 수 있을 만큼만 작성해도 알아서 찾아서 종료함. 여러개 연속으로 쓰면 모두 타겟 잡아서 종료</span><span class="token number">27</span>$ <span class="token function">docker</span> <span class="token function">ps</span> <span class="token parameter variable">-a</span>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESf6d665ae418b python:3.12-slim <span class="token string">"python3"</span> <span class="token number">17</span> minutes ago Exited <span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span> <span class="token number">17</span> minutes ago intelligent_easley7c72d2379677 python:3.12-slim <span class="token string">"-d"</span> <span class="token number">17</span> minutes ago Created adoring_jang</code></pre><h3 id="4-Docker-컨테이너-로그-확인"><a href="#4-Docker-컨테이너-로그-확인" class="headerlink" title="4) Docker 컨테이너 로그 확인"></a>4) Docker 컨테이너 로그 확인</h3><ul><li>컨테이너 실행 로그 출력: <code>docker logs <컨테이너ID></code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> imagesREPOSITORY TAG IMAGE ID CREATED SIZEdjango-app latest cbb6dff7c55a <span class="token number">2</span> days ago <span class="token number">2</span>.12GB$ <span class="token function">docker</span> run <span class="token parameter variable">-d</span> django-appbdb4eb9c03161d8427278f3cfa5e96505d52d0aa76064ad0145ee88506cdbd5b$ <span class="token function">docker</span> <span class="token function">ps</span>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMESbdb4eb9c0316 django-app <span class="token string">"/bin/bash -c 'sourc…"</span> <span class="token number">5</span> seconds ago Up <span class="token number">4</span> seconds <span class="token number">8000</span>/tcp awesome_mccarthy$ <span class="token function">docker</span> logs bdb4Applying database migrations<span class="token punctuation">..</span>.Collecting static files<span class="token punctuation">..</span>.<span class="token number">168</span> static files copied to <span class="token string">'/app/src/static'</span><span class="token builtin class-name">.</span>Starting Gunicorn<span class="token punctuation">..</span>.<span class="token punctuation">[</span><span class="token number">2024</span>-11-11 <span class="token number">17</span>:32:11 +0000<span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token punctuation">[</span>INFO<span class="token punctuation">]</span> Starting gunicorn <span class="token number">23.0</span>.0<span class="token punctuation">[</span><span class="token number">2024</span>-11-11 <span class="token number">17</span>:32:11 +0000<span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token punctuation">[</span>INFO<span class="token punctuation">]</span> Listening at: http://0.0.0.0:8000 <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">2024</span>-11-11 <span class="token number">17</span>:32:11 +0000<span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token punctuation">[</span>INFO<span class="token punctuation">]</span> Using worker: <span class="token function">sync</span><span class="token punctuation">[</span><span class="token number">2024</span>-11-11 <span class="token number">17</span>:32:11 +0000<span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token number">609</span><span class="token punctuation">]</span> <span class="token punctuation">[</span>INFO<span class="token punctuation">]</span> Booting worker with pid: <span class="token number">609</span></code></pre><h3 id="5-Docker-네트워크-관리"><a href="#5-Docker-네트워크-관리" class="headerlink" title="5) Docker 네트워크 관리"></a>5) Docker 네트워크 관리</h3><ul><li>네트워크 생성: <code>docker network create <네트워크명></code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> network create mynwbeb1bf647de5e6a2ea2debcd45a095b2c94b217a0c645e05ff33fd122ffdfe8a</code></pre><br><ul><li>컨테이너를 특정 네트워크에 연결: <code>docker run --name <컨테이너명> --network <네트워크명> <이미지명></code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> run <span class="token parameter variable">-d</span> django-appb4aa6fefecb97198ea2f7824f43e7eeb62ec3f065722b84a2d34ff9e1f834708$ <span class="token function">docker</span> run <span class="token parameter variable">--name</span> b4aa <span class="token parameter variable">--network</span> mynwApplying database migrations<span class="token punctuation">..</span>.Collecting static files<span class="token punctuation">..</span>.<span class="token number">168</span> static files copied to <span class="token string">'/app/src/static'</span><span class="token builtin class-name">.</span>Starting Gunicorn<span class="token punctuation">..</span>.<span class="token punctuation">[</span><span class="token number">2024</span>-11-11 <span class="token number">17</span>:32:11 +0000<span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token punctuation">[</span>INFO<span class="token punctuation">]</span> Starting gunicorn <span class="token number">23.0</span>.0<span class="token punctuation">[</span><span class="token number">2024</span>-11-11 <span class="token number">17</span>:32:11 +0000<span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token punctuation">[</span>INFO<span class="token punctuation">]</span> Listening at: http://0.0.0.0:8000 <span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">[</span><span class="token number">2024</span>-11-11 <span class="token number">17</span>:32:11 +0000<span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token number">1</span><span class="token punctuation">]</span> <span class="token punctuation">[</span>INFO<span class="token punctuation">]</span> Using worker: <span class="token function">sync</span><span class="token punctuation">[</span><span class="token number">2024</span>-11-11 <span class="token number">17</span>:32:11 +0000<span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token number">609</span><span class="token punctuation">]</span> <span class="token punctuation">[</span>INFO<span class="token punctuation">]</span> Booting worker with pid: <span class="token number">609</span></code></pre><br><ul><li>Docker 네트워크 리스트 확인: <code>docker network ls</code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> network <span class="token function">ls</span>NETWORK ID NAME DRIVER SCOPE63d6218decce bridge bridge <span class="token builtin class-name">local</span>8207a8266c78 <span class="token function">host</span> <span class="token function">host</span> <span class="token builtin class-name">local</span>beb1bf647de5 mynw bridge <span class="token builtin class-name">local</span>5db98f6636e1 none null <span class="token builtin class-name">local</span></code></pre><br><ul><li>사용자 정의 네트워크 삭제: <code>docker network rm <네트워크명></code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> network <span class="token function">ls</span>NETWORK ID NAME DRIVER SCOPE63d6218decce bridge bridge <span class="token builtin class-name">local</span>8207a8266c78 <span class="token function">host</span> <span class="token function">host</span> <span class="token builtin class-name">local</span>beb1bf647de5 mynw bridge <span class="token builtin class-name">local</span>5db98f6636e1 none null <span class="token builtin class-name">local</span>$ <span class="token function">docker</span> network <span class="token function">rm</span> mynwmynw$ <span class="token function">docker</span> network <span class="token function">ls</span>NETWORK ID NAME DRIVER SCOPE63d6218decce bridge bridge <span class="token builtin class-name">local</span>8207a8266c78 <span class="token function">host</span> <span class="token function">host</span> <span class="token builtin class-name">local</span>5db98f6636e1 none null <span class="token builtin class-name">local</span>$ <span class="token function">docker</span> network <span class="token function">rm</span> bridge <span class="token comment"># 사전 정의된 것에 대해서는 오류 발생</span>Error response from daemon: bridge is a pre-defined network and cannot be removed</code></pre><h3 id="6-Docker-Volume-관리"><a href="#6-Docker-Volume-관리" class="headerlink" title="6) Docker Volume 관리"></a>6) Docker Volume 관리</h3><ul><li>데이터를 저장할 볼륨 생성: <code>docker volume create <볼륨명></code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> volume create myvomyvo</code></pre><br><ul><li>볼륨을 컨테이너에 마운트: <code>docker run -d --name <컨테이너명> -v <볼륨명>:<컨테이너경로> <이미지명></code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> imagesREPOSITORY TAG IMAGE ID CREATED SIZEnginx latest 7a3f95c07812 <span class="token number">7</span> weeks ago 197MB$ <span class="token function">docker</span> run <span class="token parameter variable">-d</span> <span class="token parameter variable">--name</span> my-nginx <span class="token parameter variable">-v</span> myvo:/app/data nginx007310e795a8096434dac9a75b83e238c0a698e36f660fe0e4552cf4b2d34df5</code></pre><br><ul><li>생성된 볼륨 리스트 확인: <code>docker volume ls</code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> volume <span class="token function">ls</span><span class="token function">docker</span> volume <span class="token function">ls</span>DRIVER VOLUME NAME<span class="token builtin class-name">local</span> back_media_volume<span class="token builtin class-name">local</span> back_postgres_data<span class="token builtin class-name">local</span> back_static_volume<span class="token builtin class-name">local</span> myvo</code></pre><br><ul><li>특정 볼륨 삭제: <code>docker volume rm <볼륨명></code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> volume <span class="token function">ls</span>DRIVER VOLUME NAME<span class="token builtin class-name">local</span> back_media_volume<span class="token builtin class-name">local</span> back_postgres_data<span class="token builtin class-name">local</span> back_static_volume<span class="token builtin class-name">local</span> myvo$ <span class="token function">docker</span> volume <span class="token function">rm</span> back_postgres_databack_postgres_data<span class="token comment"># 이미 볼륨이 컨테이너에 마운트 되어있으면 삭제 불가능</span>$ <span class="token function">docker</span> <span class="token function">ps</span> <span class="token parameter variable">-a</span>CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES007310e795a8 nginx <span class="token string">"/docker-entrypoint.…"</span> <span class="token number">4</span> minutes ago Up <span class="token number">4</span> minutes <span class="token number">80</span>/tcp my-nginx <span class="token comment"># 여기에 myvo가 마운트 되어있음</span>$ <span class="token function">docker</span> volume <span class="token function">rm</span> myvoError response from daemon: remove myvo: volume is <span class="token keyword">in</span> use - <span class="token punctuation">[</span>007310e795a8096434dac9a75b83e238c0a698e36f660fe0e4552cf4b2d34df5<span class="token punctuation">]</span></code></pre><h3 id="7-Dockerfile로-이미지-빌드"><a href="#7-Dockerfile로-이미지-빌드" class="headerlink" title="7) Dockerfile로 이미지 빌드"></a>7) Dockerfile로 이미지 빌드</h3><ul><li><code>docker build -t <이미지명>:<태그> <Dockerfile 경로></code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash">$ <span class="token function">docker</span> build <span class="token parameter variable">-t</span> my-app:1.0 <span class="token builtin class-name">.</span><span class="token punctuation">[</span>+<span class="token punctuation">]</span> Building <span class="token number">0</span>.0s <span class="token punctuation">(</span><span class="token number">2</span>/2<span class="token punctuation">)</span> FINISHED <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>internal<span class="token punctuation">]</span> load build definition from Dockerfile <span class="token number">0</span>.0s <span class="token operator">=</span><span class="token operator">></span> <span class="token operator">=</span><span class="token operator">></span> transferring dockerfile: 2B <span class="token number">0</span>.0s <span class="token operator">=</span><span class="token operator">></span> <span class="token punctuation">[</span>internal<span class="token punctuation">]</span> load <span class="token builtin class-name">.</span> dockerignore <span class="token number">0</span>.0s <span class="token operator">=</span><span class="token operator">></span> <span class="token operator">=</span><span class="token operator">></span> transferring context: 2B <span class="token number">0</span>.0s <span class="token operator">=</span><span class="token operator">></span> exporting to image <span class="token number">0</span>.0s <span class="token operator">=</span><span class="token operator">></span> <span class="token operator">=</span><span class="token operator">></span> exporting layers <span class="token number">0</span>.0s <span class="token operator">=</span><span class="token operator">></span> <span class="token operator">=</span><span class="token operator">></span> writing image sha56:84b400a8fb9307f2ddc1dc29eef33c2bb664e2bdac75449d1f14e4cabaeb429 <span class="token number">0</span>.0s <span class="token operator">=</span><span class="token operator">></span> <span class="token operator">=</span><span class="token operator">></span> naming to docker.io/library/my-app <span class="token number">0</span>.0s <span class="token comment"># 플랫폼이 다를 경우에는 --platform 명령어를 사용할 것</span> $ <span class="token function">docker</span> build <span class="token parameter variable">--platform</span> linux/amd64,linux/arm64 <span class="token parameter variable">-t</span> my-app:1.0 <span class="token builtin class-name">.</span></code></pre><h3 id="8-Docker-레지스트리"><a href="#8-Docker-레지스트리" class="headerlink" title="8) Docker 레지스트리"></a>8) Docker 레지스트리</h3><ul><li>이미지 태그 지정: <code>docker tag <이미지명>:<태그> <레지스트리URL>/<이미지명>:<태그></code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">docker</span> tag my-app:1.0 my-registry-url/my-app:1.0</code></pre><br><ul><li>이미지 푸시: <code>docker push <레지스트리URL>/<이미지명>:<태그></code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">docker</span> push my-registry-url/my-app:1.0</code></pre><br><ul><li>이미지 풀: <code>docker pull <레지스트리URL>/<이미지명>:<태그></code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">docker</span> pull my-registry-ur/my-app:1.0</code></pre><h3 id="9-Docker-Compose"><a href="#9-Docker-Compose" class="headerlink" title="9) Docker Compose"></a>9) Docker Compose</h3><ul><li><strong>docker-compose.yaml</strong> 파일 기반으로 컨테이너 실행: <code>docker-compose up</code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">docker-compose</span> up</code></pre><br><ul><li>실행 중인 docker-compose 서비스를 종료하고 네트웤, 볼륨 제거: <code>docker-compose down</code></li></ul><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">docker-compose</span> down</code></pre><h3 id="10-기타-유용한-명령어"><a href="#10-기타-유용한-명령어" class="headerlink" title="10) 기타 유용한 명령어"></a>10) 기타 유용한 명령어</h3><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 컨테이너 상세정보 출력</span><span class="token function">docker</span> inspect <span class="token operator"><</span>컨테이너ID<span class="token operator">></span><span class="token comment"># 로컬 이미지 크기 확인</span><span class="token function">docker</span> image <span class="token function">ls</span> <span class="token parameter variable">--format</span> <span class="token string">"{{.Repository}}: {{.Size}}"</span><span class="token comment"># docker가 사용하는 디스크 용량 확인</span><span class="token function">docker</span> system <span class="token function">df</span><span class="token comment"># 캐시 정리</span><span class="token function">docker</span> system prune</code></pre>]]></content>
<categories>
<category> ♼ DevOps </category>
</categories>
<tags>
<tag> DevOps </tag>
<tag> Container </tag>
<tag> Docker </tag>
</tags>
</entry>
<entry>
<title>Kubernetes 정리</title>
<link href="/2024/10/12/DevOps/Kubernetes/"/>
<url>/2024/10/12/DevOps/Kubernetes/</url>
<content type="html"><![CDATA[<p>어느정도 개발공부를 한 사람이라면 Kubernetes(쿠버네티스)를 최소 한 번 이상은 접해봤을 것이다.<br>유명하다면 모두가 써봤다는 얘기고, 그말은 즉슨 무조건 공부를 해야하는 것이기 때문에(…) 오늘 날을 잡아서 개념 및 명령어를 한 번 정리해봤다.</p><h2 id="1-Kubernetes란"><a href="#1-Kubernetes란" class="headerlink" title="1. Kubernetes란?"></a>1. Kubernetes란?</h2><p>쿠버네티스는 <u>컨테이너화된 애플리케이션의 <strong>배포, 스케일링, 운영</strong>을 자동화하기 위한 오픈소스</u>이다. 즉 무료로 이용할 수 있는 프로그램이다.</p><p>이름이 긴탓에 줄여서 k8s라고 하며, Google에서 개발했으나 현재 CNCF(Cloud Native Computing Foundation)에서 <a href="https://github.com/kubernetes/kubernetes">repo</a>를 관리하고 있다.</p><p>복잡한 컨테이너 환경에서 애플리케이션이 안정적으로 동작하도록 돕는 <strong>컨테이너 오케스트레이션 도구</strong>이다.</p><h2 id="2-Kubernetes의-주요-역할"><a href="#2-Kubernetes의-주요-역할" class="headerlink" title="2. Kubernetes의 주요 역할"></a>2. Kubernetes의 주요 역할</h2><ul><li>여러 컨테이너를 효과적으로 배포 및 관리</li><li>Auto Scaling: 애플리케이션의 사용량에 따라 컨테이너 수를 자동으로 늘리거나 줄임</li><li>Self-Healing: 문제가 발생한 컨테이너를 자동으로 재시작 및 복구</li><li>Load Balancing 및 트래픽 분배 -> 시스템 과부화 방지</li><li>배포 자동화: rolling update같은 방식으로 중단 없이 배포 진행</li></ul><h2 id="3-Kubernetes의-주요-구성-요소"><a href="#3-Kubernetes의-주요-구성-요소" class="headerlink" title="3. Kubernetes의 주요 구성 요소"></a>3. Kubernetes의 주요 구성 요소</h2><img src="./1.png" width="800"><h3 id="Master-Node"><a href="#Master-Node" class="headerlink" title="Master Node"></a>Master Node</h3><p>클러스터 제어 및 관리를 담당하는 중앙 서버</p><ul><li>API Server: 클러스터 진입점으로 <code>kubectl</code> 명령어를 처리</li><li>Scheduler: 컨테이너를 어떤 노드에서 실행할지 결정</li><li>Controller Manager: 리소스 상태를 관리하고 이상 상태를 복구</li><li>etcd: 클러스터 상태 정보를 저장하는 분산 키-값 저장소</li></ul><h3 id="Worker-Node"><a href="#Worker-Node" class="headerlink" title="Worker Node"></a>Worker Node</h3><p>실제로 컨테이너가 실행되는 노드</p><ul><li>Kubelet: Master Node의 명령을 받아 컨테이너를 실행하고 상태 보고</li><li>Kube Proxy: 네트워킹을 관리하고 서비스 간의 통신 지원</li><li>Container Runtime: 컨테이너 실행 환경 (Docker, containerd 등)</li></ul><h2 id="4-Kubernetes의-resource-object"><a href="#4-Kubernetes의-resource-object" class="headerlink" title="4. Kubernetes의 resource object"></a>4. Kubernetes의 resource object</h2><h3 id="1-Pod"><a href="#1-Pod" class="headerlink" title="1) Pod"></a>1) Pod</h3><ul><li>컨테이너의 최소 단위로, 하나 이상의 컨테이너를 포함</li><li>같은 Pod 내부의 컨테이너는 네트워크와 스토리지 공유</li></ul><h3 id="2-Deployment"><a href="#2-Deployment" class="headerlink" title="2) Deployment"></a>2) Deployment</h3><ul><li>Pod를 정의하고 애플리케이션의 배포 및 업데이트 관리</li><li>롤링 업데이트, 롤백 기능 지원</li></ul><h3 id="3-Service"><a href="#3-Service" class="headerlink" title="3) Service"></a>3) Service</h3><ul><li>Pod의 네트워크 접근을 제어하며, 외부 트래픽을 내부 Pod로 전달</li><li>ClusterIP, NodePort, LoadBalancer 등</li></ul><h3 id="4-ConfigMap-Secret"><a href="#4-ConfigMap-Secret" class="headerlink" title="4) ConfigMap & Secret"></a>4) ConfigMap & Secret</h3><ul><li>ConfigMap: 환경 설정 데이터 관리</li><li>Secret: 비밀번호, 인증 토큰 같은 민감한 정보를 안전하게 저장</li></ul><h3 id="5-Volume"><a href="#5-Volume" class="headerlink" title="5) Volume"></a>5) Volume</h3><p>Pod에 영구적인 데이터를 제공하기 위한 스토리지</p><h3 id="6-Namespace"><a href="#6-Namespace" class="headerlink" title="6) Namespace"></a>6) Namespace</h3><ul><li>리소스를 그룹화하여 논리적인 구획을 제공</li><li>default, kube-system 등</li></ul><h2 id="5-Kubernetes의-추가-기능"><a href="#5-Kubernetes의-추가-기능" class="headerlink" title="5. Kubernetes의 추가 기능"></a>5. Kubernetes의 추가 기능</h2><h3 id="1-Horizontal-Pod-Autoscaler-HPA"><a href="#1-Horizontal-Pod-Autoscaler-HPA" class="headerlink" title="1) Horizontal Pod Autoscaler (HPA)"></a>1) Horizontal Pod Autoscaler (HPA)</h3><p>애플리케이션의 부하에 따라 Pod의 수를 자동으로 늘리거나 줄이는 기능</p><h3 id="2-Helm"><a href="#2-Helm" class="headerlink" title="2) Helm"></a>2) Helm</h3><p>쿠버네티스 애플리케이션의 패키지 관리자. 반복적인 배포 관리</p><h3 id="3-Network-Policy"><a href="#3-Network-Policy" class="headerlink" title="3) Network Policy"></a>3) Network Policy</h3><p>네트워크 트래픽을 제어하여 Pod 간의 통신을 관리</p><h2 id="6-Kubernetes의-동작-원리"><a href="#6-Kubernetes의-동작-원리" class="headerlink" title="6. Kubernetes의 동작 원리"></a>6. Kubernetes의 동작 원리</h2><p>사용자가 kubectl을 통해 매니페스트(YAML 파일)로 리소스를 정의하고 API Server에 전달<br>-> API Server가 스케줄러를 통해 적절한 Worker Node를 선택<br>-> 선택된 Node에서 Kubelet이 컨테이너 런타임(Docker 등)을 사용해 Pod를 생성<br>-> 네트워킹, 로드 밸런싱, 스케일링 등은 서비스 및 설정에 따라 자동으로 처리</p>]]></content>
<categories>
<category> ♼ DevOps </category>
</categories>
<tags>
<tag> DevOps </tag>
<tag> Kubernates </tag>
</tags>
</entry>
<entry>
<title>[AWS] Cloud Practitioner 시험 준비 및 후기</title>
<link href="/2024/09/30/Certificate/AWS/CloudPractitioner/"/>
<url>/2024/09/30/Certificate/AWS/CloudPractitioner/</url>
<content type="html"><![CDATA[<h2 id="AWS-사전-지식"><a href="#AWS-사전-지식" class="headerlink" title="AWS 사전 지식"></a>AWS 사전 지식</h2><ul><li>있음. CloudWatch, SQS, CloudFront, S3, EC2, Transfer Family, Route53, DynamoDB, RDS(Mysql), CloudFornation 등</li><li>따라서 개념 정리는 하루만 하고 바로 시험 문제로 들어간, 일종의 bottom-up 방식으로 공부를 진행했음.<br>만약 기초가 전혀 없다면 개념 정리는 넉넉하게 일주일 정도 잡고 문제를 푸는 것을 추천함</li></ul><h2 id="시험-준비-기간-1달-인데-빡집중한거는-1주-정도"><a href="#시험-준비-기간-1달-인데-빡집중한거는-1주-정도" class="headerlink" title="시험 준비 기간: 1달 (인데 빡집중한거는 1주 정도)"></a>시험 준비 기간: 1달 (인데 빡집중한거는 1주 정도)</h2><h3 id="1-전반적인-개념-정리-하루"><a href="#1-전반적인-개념-정리-하루" class="headerlink" title="(1) 전반적인 개념 정리: 하루"></a>(1) 전반적인 개념 정리: 하루</h3><ul><li>인터넷에 요약본 정리하면 나와있음: 너무 많아서 머리가 어지러운 나머지 하루하고 때려침. 대충 반정도는 알았어서 가능했음<ul><li><a href="https://velog.io/@chan9708/AWS-Cloud-Practitioner-%EC%99%84%EC%A0%84%EC%A0%95%EB%B3%B5-%EC%9A%94%EC%95%BD">블로그 1</a></li><li><a href="https://tbvjrornfl.tistory.com/188">블로그 2</a></li></ul></li></ul><h3 id="2-시험-문제-공부-덤프-무료"><a href="#2-시험-문제-공부-덤프-무료" class="headerlink" title="(2) 시험 문제 공부: 덤프 (무료)"></a>(2) 시험 문제 공부: 덤프 (무료)</h3><ul><li>덤프: 일부 문제의 답에 대해서 갑론을박이 있으며, 이는 chatGPT를 활용해서 맞춰보는 것을 추천함<ul><li><a href="https://www.examtopics.com/exams/amazon/aws-certified-cloud-practitioner">aws-certified-cloud-practitioner</a></li><li><a href="https://www.examtopics.com/exams/amazon/aws-certified-cloud-practitioner-clf-c02">aws-certified-cloud-practitioner-clf-c02</a></li><li>본인은 CLF-02로 시험을 봤으나 둘 다 무료분까지 1회독 진행함</li></ul></li><li>헷갈리는 개념들은 노트에 직접 적으며 깜지 진행. 문제는 총 1회독 진행, 하루에 1시간 씩 공부함</li></ul><p>이렇게 공부하니 대충 a4 5장 정도 나왔다.</p><h2 id="시험-준비물"><a href="#시험-준비물" class="headerlink" title="시험 준비물"></a>시험 준비물</h2><ul><li>신분증 2개(여권, 주민등록증) 또는 신분증 1개 + 신용카드를 준비해야 한다. 한글/영어 이름 확인을 위해서 이 둘은 필수!</li><li>당연하지만 시험장 내부에는 개인 필기구도 가져갈 수 없다. 오직 물품보관함 열쇠 + 신분증 + 안경(선택)만 허락한다</li></ul><h2 id="시험-팁"><a href="#시험-팁" class="headerlink" title="시험 팁"></a>시험 팁</h2><ul><li>기본적으로 영어 제공. 영어 외 언어 선택하면 해당 언어 번역본 + 20분 추가시간 주어짐 (인터넷에서는 한국어로 시험보면 30분 추가로 준다고 하던데, 언제부터인지 모르겠으나 일단 나는 20분 추가 시간 받음)</li><li>AWS Cloud Practitioner Certificate는 암기과목임. 초중고등학생 때 공부한 것처럼 외우기만 하면 됨</li><li>종종 AWS에서 온라인 스터디 여는데, 참여 시 50% 시험응시 할인 쿠폰을 받을 수 있음</li></ul><h2 id="시험-후기"><a href="#시험-후기" class="headerlink" title="시험 후기"></a>시험 후기</h2><ul><li>총 65문제 나왔고 검토는 1번해서 50분만에 나왔다. 내가 잘한다는 의미는 아니고, 찍거나 헷갈리는 문제는 전부 틀리는 사람인지라 굳이 시간낭비를 하기 싫었다 ㅎㅎ;;</li><li>좋았던 것은 시험 시간을 꼭 맞출 필요는 없다는 것이었는데, 오전 11시 시험으로 예약했으나 10시 20분에 도착해서 바로 시험에 들어갈 수 있었다.</li><li>시험은 <a href="https://naver.me/FqSi5ht7">SRTC</a>에서 봤으며, 시험장에 입장하기 전에 끄적일 수 있는 A4 한장을 주셨다. 코팅되어 있어서 제공해주시는 매직펜으로 맘껏 쓸 수 있었으며, 지우고 싶으면 손들면 된다고 하셨다. 근데 그렇게 끄적일게 없어서.. 일단 챙겨주시니 가져가서 잘 활용했다.</li><li>보안 개빡세다. 공항 몸수색 뺨치는 수준으로 본다. 바지 걷어서 양말을 보이거나, 안내자님 따라서 몸을 툭툭 두들겨야 하며, 이름 및 접수 기준 핸드폰 뒷자리 번호 등을 물어보셨다. 물론 컨닝을 할 계획이 없으니 당당하게 하면 된다.</li><li>합불여부는 시험 끝내면 바로 볼 수 있다. 몇 개 찍었는데 합격 나와서 기분이 좋은~ 참고로 시험점수는 840점이었다.</li><li>시험 난이도는.. 모르는거랑 헷갈리는거 몇 개 있었지만 덤프에 나왔던거 그대로 나온게 많아서 괜찮았다.</li><li>시험에 통과하면 다음 AWS 자격증 시험 50%를 할인 바우처 및 SME 참여 기회를 얻을 수 있다.</li></ul>]]></content>
<categories>
<category> 📝 Certificate </category>
</categories>
<tags>
<tag> Cloud </tag>
<tag> AWS </tag>
</tags>
</entry>
<entry>
<title>개발자 포트폴리오, 이렇게 준비해보자</title>
<link href="/2024/09/12/Retrospect/Portfolio/"/>
<url>/2024/09/12/Retrospect/Portfolio/</url>
<content type="html"><를 참고하면 되며, 여기서는 오픈소스 프로젝트를 지원하는 프로그램을 적어보고자 한다.<br>어차피 오픈소스에 기여할거면 ✨간지나게✨ 하는게 좋지 않은가 ㅎㅎ</p><p>여러 가지 프로그램이 있는데, 그 중 가장 추천하는 프로그램은 바로 NIPA에서 운영 중인 오픈소스 생태계 지원 사업이다.</p><p><br><br></p><h2 id="5-📁-FAQ"><a href="#5-📁-FAQ" class="headerlink" title="5. 📁 FAQ"></a>5. 📁 FAQ</h2><p>현재도 다양한 SW 프로그램에서 멘토로 활동하고 있는데, 취업 관련해서 많이 들어오는 질문들을 한 번 정리해보았다.</p><blockquote><h4 id="Q1-포트폴리오에서-가장-도움-됐던-활동은"><a href="#Q1-포트폴리오에서-가장-도움-됐던-활동은" class="headerlink" title="Q1. 포트폴리오에서 가장 도움 됐던 활동은?"></a>Q1. 포트폴리오에서 가장 도움 됐던 활동은?</h4><br>아무래도 `대회 수상 내역` 및 `프로젝트`가 가장 도움이 됐던 것 같다.<p>다만 이 두 가지 조건을 충족하면 매우 좋겠지만, 모두 알다시피 현실이 그렇게 녹록치 않다.<br>따라서 나는 <strong><code>프로젝트</code>는 필수</strong>로 들고가고, <strong><code>대회 수상 내역</code>은 선택적</strong>으로 가져가는 것을 추천한다.<br>(개인적으로 전공 비전공을 떠나, 대회 수상 자체는 95%의 운과 5%실력이 있어야 한다고 생각한다)</p></blockquote><blockquote><h4 id="Q2-직무와-관련-없는-프로젝트를-포함해도-될까-ex-백엔드-직무-프론트-c언어-관련-프로젝트"><a href="#Q2-직무와-관련-없는-프로젝트를-포함해도-될까-ex-백엔드-직무-프론트-c언어-관련-프로젝트" class="headerlink" title="Q2. 직무와 관련 없는 프로젝트를 포함해도 될까? (ex. 백엔드 직무 - 프론트, c언어 관련 프로젝트)"></a>Q2. 직무와 관련 없는 프로젝트를 포함해도 될까? <br>(ex. 백엔드 직무 - 프론트, c언어 관련 프로젝트)</h4><br><p>무조건 빼야한다. 넣어도 어차피 안본다.<br>포트폴리오는 <strong>자신의 역량을 보여주는 도구</strong>이기 때문에, 이 때 자기 어필을 제대로 하지 못할 경우 요즘 기고 나는 개발자 지망생들에게 묻히기 십상이다.</p></blockquote><blockquote><h4 id="Q3-포트폴리오-만들면서-전공과목-알고리즘-데이터베이스-등-학습법"><a href="#Q3-포트폴리오-만들면서-전공과목-알고리즘-데이터베이스-등-학습법" class="headerlink" title="Q3. 포트폴리오 만들면서 전공과목(알고리즘, 데이터베이스 등) 학습법"></a>Q3. 포트폴리오 만들면서 전공과목(알고리즘, 데이터베이스 등) 학습법</h4><br><p>이런 말이 있다. 칼을 썰면 무라도 썰자. 그냥 <code>프로젝트를 하면 된다</code>.<br>물론 맨 땅에 헤딩이라고, 프로젝트를 들어가면 ‘그래서 난 도대체 뭘 해야하지’라며 갈팡질팡하는 경우가 많다.<br>만약 내가 프로젝트를 전혀 해본 적이 없거나 시작점을 못찾겠다 싶으면 <strong>유튜브나 블로그, 각종 학습 사이트에 업로드된 프로젝트를 클론코딩 해보자.</strong><br>그게 어느 정도 익숙해졌다면 그 때부터 원하는 주제로 프로젝트를 진행하면 된다. 그러면 자연스럽게 컴퓨터 공부를 할 수 있다.</p><p>다만 <strong>알고리즘은 따로 공부가 필요하다.</strong> 기업연계가 아닌 이상 한정된 데이터를 가지고 작업을 해야하기 때문에, 우리가 생각하는 알고리즘들을 구현할 기회가 거의 없을 수 밖에 없다.</p></blockquote><blockquote><h4 id="Q4-프로젝트-수준은-어디까지"><a href="#Q4-프로젝트-수준은-어디까지" class="headerlink" title="Q4. 프로젝트 수준은 어디까지?"></a>Q4. 프로젝트 수준은 어디까지?</h4><br><p>될 수 있으면 <code>실서비스(배포)</code>까지 하는 것을 추천한다.</p><p>요즘은 포트폴리오 준비를 국비지원(KDT)에서 많이 하는데, 여기서 서버비용까지 지원해주고 있기 때문에 서비스 배포까지 하는 경우가 굉장히 많다. 이는 곧 시간이 갈 수록 스펙이 상향조준 된다는 의미며, 평범하게 했다가는 남들에게 치여 뽑히지 못할 가능성이 크다(…)</p><p>개인적으로 주니어 개발자라면 배포까지는 너무 오버스펙이라 생각하지만… 어쨌든간에 다른 경쟁자들 사이에서 남다른 모습을 보이기 위해서는 못해도 중간은 해야하기 때문에, 될 수 있으면 배포까지 하는 것을 추천한다.</p></blockquote><blockquote><h4 id="Q5-개발자는-학력을-안-본다는-말이-맞는가"><a href="#Q5-개발자는-학력을-안-본다는-말이-맞는가" class="headerlink" title="Q5. 개발자는 학력을 안 본다는 말이 맞는가?"></a>Q5. 개발자는 학력을 안 본다는 말이 맞는가?</h4><img src="/2024/09/12/Retrospect/Portfolio/2.png" class="" title="진짜 안본다고 생각하세요?"><br><p>개인적으로 지금 적고 있는 FAQ중 모든 사람들이 이 질문은 꼭 봐줬으면 싶다.<br>아니다. 본다. <code>무조건 본다</code>.</p><p>기업 공식 블로그나 KDT 입사 사례, 유튜브같은 곳을 보면, “비전공자인데 개발직군으로 취뽀해서 초봉 6000이상 받아요~”하는 내용을 쉽게 볼 수 있다.<br>이 사례들은 많은 비전공자들에게 희망을 주기도 하지만, 동시에 일부만 보고 전체를 판단하는 오류를 범하게 할 수 있다.<br>다들 은연 중에 알고 있을 것이다. 왜 이런 것들이 눈에 들어오는가. 바로 <strong>비전공자가 전공자랑 싸워서 개발직군에 취뽀한다 라는 것 자체가 굉장히 어렵기 때문</strong>이다.</p><p>기업 입장에서야 “우리는 전공/비전공을 가리지 않고 실력이 있으면 뽑습니다”라는 메시지를 전달하려는 의도로 만들었겠지만,<br>현실적으로 전공자는 다양한 교수님 및 전문 커리큘럼을 통해 체계적인 교육을 받을 기회가 많고, 비전공자는 이러한 리소스가 부족해 더 큰 노력이 필요한 편이다.<br>따라서 단순히 미디어에서 본 성공 사례만을 보고, 특히 비전공자 일수록 아무 노력도 하지 않았음에도 불구하고 ‘나도 저렇게 될거야’라고 희망만 가지다간 큰 낭패를 볼 수 있다.<br><br></p><p>그렇다면 개발자가 되기 위해 SW로 뛰어 든 비전공자들은 어떻게 해야하냐, <code>공부 기록</code>을 남기면 된다.<br>위에도 적었지만, 전공자들은 전문가에게 전문 커리큘럼으로 컴퓨터 공부를 하기 때문에 상대적으로 유리한 입장일 수 밖에 없다.<br>그리고 이 스펙은 <strong>ㅇㅇ대학교 컴퓨터공학과 졸업</strong> 같은 형식의 단 한줄로 압축해서 설명할 수 있는데 이것 또한 유리하게 적용될 수 밖에 없다.<br>한정된 글자수/페이지 내에서 자신이 할 수 있는 것들을 여러 개 나열해야 하는데, 비전공자일 경우 ‘이런 것을 했습니다’를 나열할 때<br>전공자는 ‘학과 졸업’ 하나로 기본적인 컴퓨터 공부를 했다는 것을 입증할 수 있으며 남은 공간에는 자기어필을 더 할 수 있기 때문이다.</p><p>즉, 비전공자들은 전공자들의 <strong>졸업</strong> 타이틀에 비빌 수 있는 스펙을 만들어놔야 기업에서도 수용을 하는데, 이러한 성과를 입증하는 방법은 결국 <code>무조건 기록</code>밖에 없기 때문에 무엇을 배우든 기록을 남기는 것을 추천한다.<br><br></p><p>말이 길어졌는데 정리하자면,</p><ul><li>기업은 (당연하게도) <strong>입증된 인재</strong>를 뽑길 원하며</li><li>공부 기록이 없는 이상 <strong>전문과정을 밟았음을 확실히 증명할 수 있는 전공자들이 유리한</strong> 것이 당연지사이다.</li><li>따라서 학력은 무조건 본다고 생각하면 된다.</li><li>비전공자일수록 전공자와의 격차를 줄이기 위해서 <code>공부기록</code>을 남기는 것을 추천한다.</li></ul></blockquote><blockquote><h4 id="Q6-취준은-언제부터-해야하는가"><a href="#Q6-취준은-언제부터-해야하는가" class="headerlink" title="Q6. 취준은 언제부터 해야하는가?"></a>Q6. 취준은 언제부터 해야하는가?</h4><br><p>이 글을 보는 당장 시작하는 것을 추천한다. 학년은 상관이 없다. 먼저 준비하는 사람이 빨리 승리한다.</p><p>미리 자기소개서, 프로젝트, 포트폴리오, 코딩테스트 등을 준비해봐야 나중에 봤을 때 뭐가 부족한지 판단하고 앞으로의 계획을 수월하게 세울 수 있기 때문이다.<br>이 블로그 말고도 인터넷에 좋은 내용들이 많기 때문에, 인터넷을 뒤져보고 주변 강연에도 참여해보면서 자신만의 스펙을 어떻게 뽐낼 수 있을지 충분히 고민하는 시간을 가졌으면 좋겠다.</p></blockquote><p><br><br></p><h2 id="6-🍀-마지막-하고-싶은-말"><a href="#6-🍀-마지막-하고-싶은-말" class="headerlink" title="6. 🍀 마지막 하고 싶은 말"></a>6. 🍀 마지막 하고 싶은 말</h2><ul><li>포트폴리오는 제발 겸손하게 작성하지 말자. 아주 유능한 것처럼 꾸미자</li><li>빠를수록 손해볼게 전혀 없다. 미리미리 준비하자. 뭐라도 미리 해놔야 나중에 봤을 때 고칠 수 있기 때문이다</li></ul><p><br><br></p><h2 id="7-이미지-출처"><a href="#7-이미지-출처" class="headerlink" title="7. 이미지 출처"></a>7. 이미지 출처</h2><ul><li><a href="https://www.saramin.co.kr/zf_user/">사람인</a></li><li><a href="https://www.miricanvas.com/ko">미리캔버스</a></li><li><a href="https://www.flaticon.com/kr/free-icons/pictogram">Flaticon</a></li><li><a href="https://namu.wiki/w/%EB%82%98%EB%AC%B4%EC%9C%84%ED%82%A4:%EB%8C%80%EB%AC%B8">나무위키</a></li><li><a href="https://www.oss.kr/">OSS</a></li><li>그 외 직접 제작</li></ul>]]></content>
<categories>
<category> 🎈 Retrospect </category>
</categories>
<tags>
<tag> Retrospect </tag>
<tag> Job </tag>
</tags>
</entry>
<entry>
<title>OAuth2.0를 알아보자</title>
<link href="/2024/08/20/Security/Oauth2/"/>
<url>/2024/08/20/Security/Oauth2/</url>
<content type="html"><![CDATA[<p>요즘 로그인 및 회원가입 구현 시 필수라는 Oauth2.0에 대해서 개념을 자세하게 톺아보고자 한다.</p><h2 id="OAuth란"><a href="#OAuth란" class="headerlink" title="OAuth란?"></a>OAuth란?</h2><p>풀네임으로는 Open Authorization으로 부르며, 웹 및 애플리케이션 인증 및 권한을 부여하는 개방형 표준 프로토콜이다.</p><p>설명에 앞서, 일단 유명 포털의 개발 문서에서 정의된 내용을 한 번 가져와봤다.</p><blockquote><p>이 프로토콜에서는 third-party 애플리케이션이 사용자의 리소스에 접근하기 위한 절차를 정의하고 서비스 제공자의 API를 사용할 수 있는 권한을 부여합니다.<br>대표적으로 네이버 로그인, 구글 로그인과 같은 소셜 미디어 간편 로그인이 있습니다.<br>OAuth2.0을 사용해 third-party 애플리케이션이 사용자의 소셜미디어 프로필 정보에 접근할 수 있도록 합니다.<br>B2B PRISM Live Studio 역시 OAuth2.0을 사용하여 권한을 관리하기 때문에 OAuth2.0의 기본 개념을 안내하고, 권한 부여 방법을 설명합니다.</p><p>출처: <a href="https://guide.ncloud-docs.com/docs/b2bpls-oauth2">NCP 개발 문서</a></p></blockquote><p>어느 정도 개발자 짬이 찬 사람이라면 바로 이해할 수 있겠지만, 개발에 입문한지 별로 안됐거나 개발 문서 읽는게 아직 익숙치 않은 사람들은 뭔 소린가 싶을 것이다.</p><p>쉽게 설명하자면, <code>OAuth는 다른 사이트, 앱에서 소셜 회원가입/로그인 (또는 간편 회원가입/로그인이라고 함)을 할 때 사용되는 것</code>이라고 보면 된다.<br>가령 어떤 사이트에 로그인을 할 때 <strong>Google로 로그인하기</strong>, <strong>Naver로 로그인하기</strong>가 보인다면 이 때 OAuth를 사용한다는 의미이다.</p><p><br><br></p><h2 id="OAuth-“2-0”"><a href="#OAuth-“2-0”" class="headerlink" title="OAuth “2.0”"></a>OAuth “2.0”</h2><p>인터넷에 검색해보면 대부분 <code>2.0</code>이라는 버전을 찾을 수 있는데, 현재 대중적으로 사용하는 버전이 <code>2.0</code>이기 때문이다.</p><p>즉 이전 버전(=1.0)이 있었으며, 이전 버전에서 보완할 점이 생겨서 2.0이 나왔다고 생각하면 된다.</p><p>이전에 사용한 것에서 어떤 문제가 있었는지, 그리고 최근에는 왜 2.0을 사용하는지 알아보자.</p><h3 id="1-기존-인증-방식-Basic-Authentication"><a href="#1-기존-인증-방식-Basic-Authentication" class="headerlink" title="(1) 기존 인증 방식: Basic Authentication"></a>(1) 기존 인증 방식: Basic Authentication</h3><p>어쨌든간에 개발자 입장에서 로그인 한 유저에게 프로그램 접근 권한을 주기 위해서는 인증이 된 유저라고 표시를 해야하긴 한다.</p><p>따라서 기존에는 Basic Authentication (흔히 Auth라고 부름)에 따라, 애플리케이션에 사용자의 아이디 & 비밀번호를 직접 제공해 접근 권한을 줬다.</p><p>하지만 다음의 문제가 항상 거론되었고, 이 때문에 OAuth 1.0이 생겨났다.</p><ul><li>보안 취약성: 클라이언트가 사용자의 자격 증명을 저장하거나 전송하는 과정에서 유출 위험</li><li>권한 관리 불가: 특정 자원에 대한 제한적인 권한 부여가 불가능. (모든 권한이 열림)</li><li>복잡성 증가: 사용자 비밀번호가 변경되면, 이를 사용하는 모든 서비스에서 수정해야 함</li></ul><p>한줄 요약하면 <strong>해킹 당하면 모든 정보가 털려서 문제</strong>라는 의미이다.</p><h3 id="2-OAuth-1-0의-등장-및-제한점"><a href="#2-OAuth-1-0의-등장-및-제한점" class="headerlink" title="(2) OAuth 1.0의 등장 및 제한점"></a>(2) OAuth 1.0의 등장 및 제한점</h3><h5 id="개발-배경"><a href="#개발-배경" class="headerlink" title="개발 배경"></a>개발 배경</h5><p>소프트웨어는 나날이 발전하고 있고, 이 때문에 사람들은 보안에 대해 깊게 생각하게 되었다.<br>그래서 나온 개념이 바로 OAuth 1.0이다.</p><p>개발자 입장에서는 보안을 되게 민감하게 받아들여야 하고, 하지만 관리가 매우 빡세다보니 구글이나 네이버같이 <strong>(주로) 대기업에서 이미 구현해둔 인증 로직을 가져와서 사용</strong>하는 것이다.<br>대기업에서 구현한 인증 로직은 아무래도 중소규모 기업들에 비해 보안 관리가 빡셀 것이며, 만약에 정보가 털렸다고 해도 책임이 대기업에게 있지 우리같은 소시민에게는 없기 때문이다.<br><del>폭탄 돌리기</del><br><del>물론 구현 잘못해서 정보 노출되게 코딩하면 우리 잘못이긴 하다</del></p><p>물론 그 외에도, 이런 인증 로직 하나 구현하는게 좀 빡센 편이라 이미 구현한거 가져와서 개발 시간을 아끼는겸 사용하기도 한다.</p><h5 id="Auth와-다른-점"><a href="#Auth와-다른-점" class="headerlink" title="Auth와 다른 점"></a>Auth와 다른 점</h5><p>OAuth 1.0에서는 남이 구현한 사용자 인증 로직을 가져오는 것이기 때문에, 내가 해당 인증 로직을 가져와도 되는가를 증명할 수단이 필요하다. 이것이 바로 <code>HMAC-SHA1 (서명 기반 인증)</code>이다.<br>이 로직을 이용하면 기존에 구현된 인증 로직을 바탕으로, 아이디 및 비밀번호를 넣으면 접근 권한을 받아올 수 있다.</p><h5 id="한계점"><a href="#한계점" class="headerlink" title="한계점"></a>한계점</h5><ul><li>복잡한 프로세스: 요청마다 일일이 서명 생성 및 검증이 필요 -> 구현 및 디버깅이 어려우며, 개발자에게 너무 많은 학습을 요구함</li><li>확장성 부족: 특정 인증/권한 시나리오에 맞춰 설계되어 다양한 클라이언트 유형(SPA, 모바일 애플리케이션 등)에 적용하기 어려움</li><li><strong>TSL 의존성 부족</strong>: 사실 상 원인<ul><li>서명으로 보안은 강화했으나, TLS를 필수로 요구하지 않아 <strong>Man-in-the-Middle</strong>에 매우 취약적</li><li>(참고) Man-in-the-Middle(중간자 공격): 두 당사자 간의 통신을 가로채서 조작 및 엿듣는 사이버 공격 방식<blockquote><p>(위치 선정)<br>공격자는 클라이언트(사용자)가 사용하고 있는 wifi에 접속함<br>그리고 클라이언트와 서버 사이의 통신 경로에 잠복</p><p>(통신 가로채기)<br>이 때 클라이언트가 서버에게 요청을 보냄<br>서버에 도달하기 전에 해당 요청을 공격자가 가로챔<br>클라이언트가 요청한 정보를 수정하거나 읽고 서버에 전달</p><p>(응답 가로채기)<br>마찬가지로, 서버에서 클라이언트에게 보낸 응답도 공격자가 가로챔<br>서버가 보낸 응답 내용을 수정하거나 읽고 클라이언트에게 전달</p></blockquote></li></ul></li></ul><h3 id="3-OAuth-2-0의-등장"><a href="#3-OAuth-2-0의-등장" class="headerlink" title="(3) OAuth 2.0의 등장"></a>(3) OAuth 2.0의 등장</h3><p>이렇게 OAuth 1.0의 한계를 극복하고자 나온 것이 바로 OAuth 2.0이다.</p><ul><li>프로세스 간소화: 서명 대신 <code>Access Token</code>을 사용해서 요청을 단순화</li><li>확장성 및 표준화<ul><li>확장 가능한 구조로, 추가적인 인증 메커니즘(JWT, OpenID Connect 등)과 쉽게 통합 가능</li><li>다양한 플랫폼과 서비스(Google, Facebook, GitHub 등)에서 표준으로 채택</li><li>다양한 클라이언트 유형 지원<ul><li>다양한 Grant Type 제공:<ul><li>Authorization Code Grant: 서버 사이드 애플리케이션.</li><li>Implicit Grant: 브라우저 기반 애플리케이션.</li><li>Client Credentials Grant: 서버 간 통신.</li><li>Resource Owner Password Grant: 신뢰할 수 있는 클라이언트.</li></ul></li><li>각 시나리오에 맞는 유연한 인증 방식 제공.</li></ul></li></ul></li><li>TSL 필수 사용: 데이터 전송 중에 보안을 보장하여 데이터의 무결성 입증 가능</li></ul><br><p>기능이 개선이 되었지만, 이것이 그렇다고 ✨만능✨인 것은 아니다.<br>현재 크게 두 가지 단점이 있는데, 바로</p><ul><li>초기 설정이 까다롭고</li><li><strong>Access Token</strong>이 유출되면 악용될 가능성이 매우 높아지기 때문이다.</li></ul><p>이 또한 언젠가 해결해야 하는 문제로 토론이 이루어지고 있으나, 현재까지로는 토큰만 유출 안되면 이론상 완벽하기 때문에 다들 바로 표준으로 채택한 것이다.<br>따라서 2.0이 2012년에 나왔는데, 현재까지 3.0은 나오지 않은 상태이다.</p><img src="./2.png" width="800"><h3 id="4-OAuth-2-0-주요-용어"><a href="#4-OAuth-2-0-주요-용어" class="headerlink" title="(4) OAuth 2.0 주요 용어"></a>(4) OAuth 2.0 주요 용어</h3><ul><li>Resource Owner (자원 소유자)<ul><li>자원의 주인. 일반적으로 사용자를 지칭함</li><li>ex) Facebook 계정을 가진 사용자</li></ul></li><li>Client (클라이언트)<ul><li>자원 소유자가 허용한 자원에 접근하려는 애플리케이션</li><li>ex) 자신의 Google Drive에 파일을 업로드하는 서비스</li></ul></li><li>Authorization Server (인증 서버)<ul><li>클라이언트가 인가 코드 또는 토큰을 요청하는 서버</li><li>예: Google, Facebook 등</li></ul></li><li>Resource Server (자원 서버)<ul><li>보호된 자원이 저장된 서버</li><li>예: Google Drive API 서버</li></ul></li><li>Access Token (액세스 토큰)<ul><li>클라이언트가 자원 서버에 접근할 때 사용하는 임시 키</li><li>만료 시간이 있음</li></ul></li></ul><h3 id="5-OAuth-2-0-작동-방식"><a href="#5-OAuth-2-0-작동-방식" class="headerlink" title="(5) OAuth 2.0 작동 방식"></a>(5) OAuth 2.0 작동 방식</h3><img src="./1.png" width="500"><p>출처: <a href="https://developers.google.com/identity/protocols/oauth2?hl=ko">GCP 개발 문서</a></p><ol><li><strong>Request token</strong><ul><li>사용자(클라이언트)는 로그인을 시도함. 이 때 Google이나 Naver같은 소셜 로그인을 선택함 = 사용자는 사용자 권한을 얻기 위해 인증을 받아야함</li><li>이때 사용하는 토큰은 업체마다 구현이 다름: 개발문서를 꼭 참고할 것</li></ul></li><li><strong>Authorization code</strong><ul><li>사용자가 인증 서버에서 로그인을 완료하면, 인증 서버는 Authorization code를 redirect url로 전달함</li><li>이 때 code는 임시로, 시간이 지나면 다시 재발급을 받아야 함</li></ul></li><li><strong>Exchange code for token & Token response</strong>: code를 이용해서 curl 요청을 보냄으로써 <code>Access token</code>을 발급함</li><li><strong>Use token to call API</strong><ul><li>API를 요청할 때, Access token을 사용해서 사용자 정보를 인증함</li><li>설명을 위해 로그인을 예시로 들었기 때문에, 여기서는 login API가 사용될 것이고 인증이 잘 됐다면 바로 로그인이 될 것임</li></ul></li></ol>]]></content>
<categories>
<category> 🔐 Security </category>
</categories>
<tags>
<tag> Security </tag>
<tag> Auth </tag>
<tag> OAuth2 </tag>
</tags>
</entry>
<entry>
<title>Container 정리</title>
<link href="/2024/07/12/DevOps/Container/"/>
<url>/2024/07/12/DevOps/Container/</url>
<content type="html"><![CDATA[<p>개발을 하다보면 아무래도 docker를 많이 쓰게 될텐데, 그 때 컨테이너 어쩔저쩔~~ 이라는 개념이 나오면서 사람들의 머리가 아파지기 시작한다.<br>따라서 컨테이너에 대해 개념을 잡고 싶은 사람이라면 이 글을 잘 읽어보길 추천한다. 배포 세팅(특히 devops, cloud native)에서 많이 언급되는 개념이기 때문이다.</p><h2 id="1-Container란"><a href="#1-Container란" class="headerlink" title="1. Container란"></a>1. Container란</h2><p>컨테이너는 애플리케이션과 필요한 라이브러리, 종속성을 하나로 묶어 어디서나 실행할 수 있는 일종의 <strong>가벼운 실행 환경</strong>이다.</p><p>따라서 특정 OS나 환경에 의존하지 않고 동일하게 실행된다는 의미다.</p><blockquote><p>쉽게 풀어보자면, 프로젝트를 진행하는데 A는 Windows에서, B는 MacOS에서 진행한다고 쳐보자.<br>따라서 각 환경마다 세팅이 다르기 때문에 각자 라이브러리 및 종속성을 같은 세팅으로 다운받더라도 오류가 날 수 있다는 의미다.<br>이 때 컨테이너를 사용하면 OS가 다름에도 불구하고 동일하게 프로그램이 실행된다. </p></blockquote><h2 id="2-Container에서-사용하는-중요-개념"><a href="#2-Container에서-사용하는-중요-개념" class="headerlink" title="2. Container에서 사용하는 중요 개념"></a>2. Container에서 사용하는 중요 개념</h2><p>말로만 적으면 이해가 어렵기 때문에 시나리오를 하나 정의해서 설명을 해보도록 하겠다.</p><blockquote><p><code>상황</code></p><ul><li>A: Windows 사용자, B: Macbook 사용자</li><li>이 둘은 팀플로 <strong>Python Flask 웹 애플리케이션</strong>을 개발 중</li><li>A는 로컬 Windows에서, B는 로컬 Macbook에서 작업 중임 = 프로젝트 실행 환경이 다름</li><li>A는 컨테이너 기술을 사용하여 동일한 환경에서 실행될 수 있도록 설정하고 이를 B에게 공유하려고 함</li></ul></blockquote><table><thead><tr><th align="center">개념</th><th align="center">설명</th><th align="center">예시</th></tr></thead><tbody><tr><td align="center">Container</td><td align="center">애플리케이션 실행 환경</td><td align="center">- A는 Python Flask 애플리케이션을 실행하기 위해 컨테이너를 사용함<br>- B는 A가 만든 컨테이너를 그대로 실행하면 동일한 환경에서 앱이 실행됨</td></tr><tr><td align="center">Container Image</td><td align="center">실행 환경을 템플릿으로 저장</td><td align="center">- A는 컨테이너 실행을 위한 환경(Python, Flask, 그 외 기타 requirements.txt 의존성 모듈)을 이미지로 저장</td></tr><tr><td align="center">Container Runtime</td><td align="center">컨테이너를 실행 및 관리</td><td align="center">- A와 B 모두 컨테이너 런타임을 사용하여 컨테이너를 실행</td></tr><tr><td align="center">Container Orchestration</td><td align="center">여러 컨테이너의 배포, 스케일링, 관리 등을 자동화</td><td align="center">- A와 B의 프로젝트가 성장하며 트래픽이 증가하면, 오케스트레이션 도구로 컨테이너를 확장</td></tr><tr><td align="center">Namespaces</td><td align="center">컨테이너의 리소스(CPU, 메모리 등) 격리</td><td align="center">- Flask 웹 컨테이너 / PostgreSQL 데이터베이스 컨테이너 / Redis 캐시 컨테이너 (각각 분리)<br>- 컨테이너별로 독립된 네트워크 스택(IP주소, 포트, 라우팅 테이블 등)을 가짐<br>- A의 로컬 시스템에서 실행 중인 프로세스를 확인할 때, 컨테이너의 내부 프로세스를 검색할 수 없음</td></tr><tr><td align="center">CGroups(Control Groups)</td><td align="center">리소스 사용량 제한</td><td align="center">- Flask 웹 컨테이너 / PostgreSQL 데이터베이스 컨테이너 / Redis 캐시 컨테이너 (각각 분리)<br>- A가 컨테이너를 생성할 때 한 쪽 컨테이너로만 너무 많이 리소스를 사용하지 않도록 제어</td></tr><tr><td align="center">Networking</td><td align="center">컨테이너 간 외부 통신</td><td align="center">- Flask 웹 컨테이너 / PostgreSQL 데이터베이스 컨테이너 / Redis 캐시 컨테이너 (각각 분리)<br>- A와 B는 웹 컨테이너와 데이터베이스 컨테이너를 연결하여 사용</td></tr><tr><td align="center">Registry</td><td align="center">컨테이너 이미지를 저장 및 배포</td><td align="center">- A는 컨테이너 이미지를 Hub에 업로드하여 B와 공유<br>- B는 Hub에서 이미지를 다운받아 사용</td></tr></tbody></table><h2 id="3-Container-VS-VM-Virtual-Machine"><a href="#3-Container-VS-VM-Virtual-Machine" class="headerlink" title="3. Container VS VM(Virtual Machine)"></a>3. Container VS VM(Virtual Machine)</h2><table><thead><tr><th align="center">Container</th><th align="center">Virtual Machine</th></tr></thead><tbody><tr><td align="center">Kernal 공유</td><td align="center">Hypervisor 기반</td></tr><tr><td align="center">빠른 속도, 가벼움, 이식성</td><td align="center">높은 격리성, 완전한 OS 제공</td></tr></tbody></table><h3 id="Kernal-커널-서로-사이좋게-양보하며-컴퓨터-자원-공유"><a href="#Kernal-커널-서로-사이좋게-양보하며-컴퓨터-자원-공유" class="headerlink" title="Kernal (커널): 서로 사이좋게 양보하며 컴퓨터 자원 공유"></a>Kernal (커널): 서로 사이좋게 양보하며 컴퓨터 자원 공유</h3><ul><li>OS의 핵심 부분으로, HW와 SW간의 다리 역할</li><li>애플리케이션이 하드웨어 자원(CPU, 메모리, 디스크, 네트워크 등)을 사용할 수 있도록 중개</li></ul><blockquote><p><code>상황</code> </p><ul><li>C, D, E는 각각 Flask, PostgreSQL, Redis로 실행 중</li><li>CPU는 4코어, 메모리는 8GB로 설정</li></ul><p><code>예시</code></p><ul><li>C가 러닝 중일 때 (D와 E는 유휴 상태):<ul><li>C(Flask) 가 모든 CPU와 메모리를 사용</li><li>다른 컨테이너(D, E)가 비활성 상태이므로 커널은 자원을 C에 최대한 배분</li></ul></li><li>D(PostgreSQL) 러닝 시작: 커널이 자원을 동적으로 조정<ul><li>C(Flask)** 가 CPU 2코어, 메모리 4GB를 사용하도록 줄임</li><li>D(PostgreSQL)*에게 CPU 2코어, 메모리 4GB를 배분</li><li>자원이 부족할 경우 <strong>cgroups(Control Groups)</strong> 설정에 따라 특정 컨테이너(C 또는 D)의 자원을 제한</li></ul></li><li>D와 E가 동시에 러닝 시작: 자원이 더 많이 나눠짐<ul><li>C(Flask): CPU 1코어, 메모리 3GB</li><li>D(PostgreSQL): CPU 2코어, 메모리 3GB</li><li>E(Redis): CPU 1코어, 메모리 2GB</li></ul></li></ul></blockquote><h3 id="Hypervisor-하이퍼바이저-사이가-안좋아서-자원을-빌리되-서로-공유하지-않음"><a href="#Hypervisor-하이퍼바이저-사이가-안좋아서-자원을-빌리되-서로-공유하지-않음" class="headerlink" title="Hypervisor (하이퍼바이저): 사이가 안좋아서 자원을 빌리되 서로 공유하지 않음"></a>Hypervisor (하이퍼바이저): 사이가 안좋아서 자원을 빌리되 서로 공유하지 않음</h3><ul><li>가상화를 위한 소프트웨어</li><li>물리적 하드웨어(= 실제 컴퓨터)에서 여러 개의 VM을 실행할 수 있게함</li></ul><blockquote><p><code>상황</code></p><ul><li>C, D, E는 각각 Windows, Ubuntu, CentOS로 실행 중<br>CPU는 8코어, 메모리는 16GB로 설정</li></ul><p><code>예시</code></p><ul><li>C가 실행 중일 때 (D와 E는 비활성 상태):<ul><li>C(Windows)가 CPU 8코어, 메모리 16GB를 사용</li><li>다른 VM(D, E)이 비활성 상태이므로 하이퍼바이저는 모든 자원을 C에 배분</li></ul></li><li>D(Ubuntu)가 실행을 시작하면: 하이퍼바이저가 자원을 동적으로 조정<ul><li>C(Windows): CPU 4코어, 메모리 8GB</li><li>D(Ubuntu): CPU 4코어, 메모리 8GB</li><li>각 VM은 독립된 OS와 애플리케이션을 실행하며 서로 영향을 주지 않음</li></ul></li><li>D와 E(CentOS)가 동시에 실행을 시작하면: 자원이 세 VM으로 나눠짐<ul><li>C(Windows): CPU 3코어, 메모리 6GB</li><li>D(Ubuntu): CPU 3코어, 메모리 6GB</li><li>E(CentOS): CPU 2코어, 메모리 4GB</li><li>각 VM은 독립된 OS와 애플리케이션을 실행하며 서로 영향을 주지 않음<br>=> 많아지면 컴퓨터 속도 저하 원인</li></ul></li></ul></blockquote><h2 id="4-Container-도구들"><a href="#4-Container-도구들" class="headerlink" title="4. Container 도구들"></a>4. Container 도구들</h2><p>(하나씩 글 작성 ing. 작성할 때마다 링크 추가 예정)</p><h3 id="Container-Runtime"><a href="#Container-Runtime" class="headerlink" title="Container Runtime"></a>Container Runtime</h3><ul><li>Docker: 컨테이너 생태계를 주도한 대표적인 런타임</li><li>Containerd: Docker의 핵심 런타임으로 분리되어 Kubernetes에서 직접 사용 가능</li><li>Podman: 데몬리스 컨테이너 실행환경으로 Docker의 대체제</li><li>CRI-O: Kubernetes와 호환되는 경량 런타임</li></ul><h3 id="Container-Ochestration"><a href="#Container-Ochestration" class="headerlink" title="Container Ochestration"></a>Container Ochestration</h3><ul><li>Kubernetes: 가장 널리 사용되는 컨테이너 오케스트레이션 도구. 자동 스케일링, 복구, 배포 지원</li><li>Docker Swarm: 간단한 오케스트레이션에 적합한 Docker 내장 도구</li><li>Nomad: HashiCorp에서 개발한 경량 오케스트레이션 도구</li></ul><h3 id="Container-Image"><a href="#Container-Image" class="headerlink" title="Container Image"></a>Container Image</h3><ul><li>Buildah: Docker 없이 이미지를 빌드 가능</li><li>Kaniko: 클라우드 환경에서 안전하게 이미지 빌드</li></ul><h3 id="컨테이너-보안-도구"><a href="#컨테이너-보안-도구" class="headerlink" title="컨테이너 보안 도구"></a>컨테이너 보안 도구</h3><ul><li>Falco: 실시간 컨테이너 보안 이벤트 감지</li><li>Aqua Security: 컨테이너 환경 보안을 포괄적으로 관리</li></ul>]]></content>
<categories>
<category> ♼ DevOps </category>
</categories>
<tags>
<tag> DevOps </tag>
<tag> Container </tag>
</tags>
</entry>
<entry>
<title>[컨퍼런스] Tech Summit Silicon Valley 2024 후기 - 2일차</title>
<link href="/2024/06/22/Conference/24-silicon-valley-2/"/>
<url>/2024/06/22/Conference/24-silicon-valley-2/</url>
<content type="html"><![CDATA[<h2 id="1-PANEL-SESSION-The-Future-of-Tech-Startups-Trends-and-Predictions"><a href="#1-PANEL-SESSION-The-Future-of-Tech-Startups-Trends-and-Predictions" class="headerlink" title="1. PANEL SESSION: The Future of Tech Startups: Trends and Predictions"></a>1. PANEL SESSION: The Future of Tech Startups: Trends and Predictions</h2><img src="./1.jpeg" width="500"><p>여기서는 유명 대기업 테크기업부터 스타트업까지 모두 모여서 이야기를 진행했다.<br>주제가 주제다보니까 당연하게도 AI와 연관되어 질문이 많이 나왔는데, 내용은 대략적으로 이렇게 있었다.</p><ul><li>AI가 발전하는 과정에서, 우리는 앞으로 정확한 솔루션/철저한 보안 관련 쪽으로 신경을 많이 써야한다.</li><li>데이터의 퀄리티가 올라가고 있기 때문에 갈수록 비싸질 것이다. 모델도 그 비싼 데이터로 운영되기 때문이다.</li><li>Intrastructure적으로는 챌린지가 될 것이다. 여기도 결국 돈이 연관되어 있기 때문이다.</li><li>AI라고 무턱대고 도전하는건 지양한다. 예전에 암호화폐 유행했었을 때도 다들 그쪽으로 뛰어들었는데, 결과가 많이 좋지 않았다. 어느 정도 잘 알아보고 하는게 좋을 것 같다.</li><li>Founder라면 무조건 공부가 필요하다. 이것저것 잡다하게 최대한 공부해야한다. 그리고 솔루션이 scalable한지, 싼지 알아봐야 한다.</li></ul><h2 id="2-Unraveling-Tomorrow-Mapping-the-Next-20-Years-of-Technological-Evolution"><a href="#2-Unraveling-Tomorrow-Mapping-the-Next-20-Years-of-Technological-Evolution" class="headerlink" title="2. Unraveling Tomorrow: Mapping the Next 20 Years of Technological Evolution"></a>2. Unraveling Tomorrow: Mapping the Next 20 Years of Technological Evolution</h2><img src="./2.jpeg" width="500"><p>이 세션에서는 IoT, Bio, Eco, VR/AR 등 다양한 필드에서의 변화 및 전망을 발표했다.<br>여기서도 결국 하는 얘기는 같았는데, 데이터가 점점 쌓일수록 퀄리티가 올라가며, 가격이 비싸질 것이라는 얘기였다.</p><p>여기서는 세션 제목에 Technological이 붙어서 그런지 개발자만 참여하는 기적(?)이 일어나서 기술적으로 깊게 토론하는 시간을 가질 수 있었다.</p><ul><li>IoT쪽도 지금 AI를 도입하는 중이다. 근데 여기도 Cloud 환경을 이용하는 경우가 많기 때문에 Infrastructure쪽으로 일단 cost조절을 최우선으로 두고 개발하고 있다.<ul><li>Cloud는 AWS가 가장 편한데 비싸다. 차라리 GCP를 사용하는게 더 낫다. AWS보다는 접근성이 좀 떨어지는데 가격면에서는 좋다.</li><li>근데 IaC가 나오면서 AWs, GCP, Azure도 사용하기 편해졌다. Terraform을 사용하면 이 모든 것들을 관리할 수 있다. 아직 이걸 다루는 사람이 부족한 편인 것 같더라.</li><li>Terraform 자체를 사용하는 것은 좋은 아이디어인데, 그게 오픈소스다보니까 불안정한면이 있긴 하다. 그런데 AI기반 산업발전속도가 빠르다보니 오픈소스가 안정화되기 전에 치고 올라가버리니 사용이 애매하다. -> 그건 어쩔 수 없는 것 같다. 그저 우리가 최대한 기여하는 수밖에 없다. 원래 여기 업계는 빨리 변하지 않느냐</li></ul></li></ul><h2 id="3-How-AI-is-transforming-skill-development-and-validation-of-the-future-of-work"><a href="#3-How-AI-is-transforming-skill-development-and-validation-of-the-future-of-work" class="headerlink" title="3. How AI is transforming skill development and validation of the future of work"></a>3. How AI is transforming skill development and validation of the future of work</h2><img src="./3.jpeg" width="500"><p>이 세션은 재밌게 봤는데, 발표자분이 NLP에 10년 넘게 종사하신 분이었기 때문이다.<br>자신이 개발한 기술을 예시로 NLP가 어떻게 발전했는지 얘기했는데, 내가 NLP 프로젝트를 하면서 놓쳤던 부분에 대해 자연스럽게 짚어주시는걸 보고 신기하다는 느낌을 받았다.<br>참고로 이분이 강조하신 것도 다른 세션과 거의 동일했다.</p><ul><li>앞으로는 인공지능 퀄리티가 더 좋아질 것이다. 즉 서비스 제공 질이 더 좋아질 것이다.</li><li>즉 우리는 이거를 어떻게 “활용”하는지에 관건이 달렸다.</li><li>개발자 입장에서도 어떻게 퀄리티 높은 모델을 제공할건지 고민해야 할 필요성이 있다.<br>일단 좋은 모델을 만들기 위해서는 좋은 데이터가 필요하며, 이 과정에서 데이터 전처리의 중요성이 더 커지고 있다.</li><li>투자자도 공부를 해야한다. AI/개발에 대해 전혀 모르는 상태에서 투자할 것이 아니라, 데이터의 퀄리티가 어떤지를 파악하는 눈을 길러야 한다. 많은 기업들에서 쓰레기 데이터로 학습을 시켜 돈을 낭비하는 경우가 많은데, 이를 알아봐야 한다.<ul><li>GPT기술이 많이 발전했기 때문에 이 모델들에게 물어보면 어느 정도 사전 지식을 얻을 수 있을 것이다.</li></ul></li><li>(정리) 앞으로 인공지능 산업은 모델이 아닌 “퀄리티”로 승패를 나눌 것이다. 이 과정에서 데이터 전처리/자동화의 중요성은 더 커질 것이다.</li></ul><h2 id="2일차-후기"><a href="#2일차-후기" class="headerlink" title="2일차 후기"></a>2일차 후기</h2><ul><li><p>이날따라 AI에 대한 깊은 토론이 진행됐던 것 같다. 공식 석상에서 기술적인 얘기는 안했다만, 다들 한결같이 “데이터 전처리”, “자동화”에 강조를 두는 것을 보면 앞으로의 AI개발에 이를 눈여겨봐야 할 것 같다는 생각이 들었다.</p></li><li><p>이 날도 1일차와 동일하게 세션이 끝나고 개발자들끼리 모여서 대화의 장을 펼쳤다.<br>영어로 대화했기 때문에 정신집중 하느라 너무 피곤했는데, 다들 그거 감안하고 나한테 말을 걸어주더라ㅋㅋㅋㅠㅠㅠ 참 따뜻한 사람들이다 ㅎㅎㅎ</p><p>대화 내용을 요약하면 아래와 같다.</p><ul><li>이 날은 데이터에 대해서 심도 있게 대화를 나눴는데, 사람 사는게 다 거기서 거기인지 생각이 동일한 곳이 많았다.<br>대표적으로 데이터 정제에 관해서였는데, 데이터 정제가 까다롭다보니 기술+시간 비용이 크게 드는 편이라고 한다.<br>그런데 비전공자들(특히 비전공자 CEO같은 사람들)이 이것조차 모르는 상태에서 투자를 계속하다보니 전체 투자금의 30% 이상을 엉뚱한 곳에 돈을 사용하면서 최적의 결과물을 요구한다며 한숨을 쉬더라.</li><li>어쨌든간에 오픈소스 면에서는 데이터 정제 쪽으로 코드가 있으면 여러모로 SW산업에 긍정적인 영향을 미칠 것 같다는 얘기가 나왔다.</li><li>그 외로는 서로 회사에 관한 얘기와 앞으로의 핫이슈 프레임워크/라이브러리에 대한 토론을 나눴다. 내가 모르는 오픈소스들을 많이 접할 수 있어서 한층 더 똑똑해진 기분이 들었다.</li></ul></li><li><p>평일에 열리다보니 다들 회사 <-> 컨퍼런스를 오가느라 행사가 생각보다 시끌벅쩍하지는 않았다. 다만 시간대마다 다양한 사람들을 만날 수 있어서 재밌었던 것 같다. (체감상으로는 한 1000명 정도 온듯..?)<br>다음에 기회가 된다면 또 가서 사람들이랑 대화를 나눠보고 싶은 생각이 들었다 😁</p></li></ul>]]></content>
<categories>
<category> ✈️ Conference </category>
</categories>
<tags>
<tag> Conference </tag>
</tags>
</entry>
<entry>
<title>[컨퍼런스] Tech Summit Silicon Valley 2024 후기 - 1일차</title>
<link href="/2024/06/21/Conference/24-silicon-valley-1/"/>
<url>/2024/06/21/Conference/24-silicon-valley-1/</url>
<content type="html"><![CDATA[<h2 id="그-많고-많은-컨퍼런스-중-실리콘밸리를-선택한-이유는"><a href="#그-많고-많은-컨퍼런스-중-실리콘밸리를-선택한-이유는" class="headerlink" title="그 많고 많은 컨퍼런스 중 실리콘밸리를 선택한 이유는?"></a>그 많고 많은 컨퍼런스 중 실리콘밸리를 선택한 이유는?</h2><p>개발자들의 세계 최고의 필드 “실리콘밸리”에서 열리는 컨퍼런스라는 것도 의미가 있었지만, 나는 그 무엇보다 <u>실리콘밸리 개발자들과 최신 기술 동향에 대해 ‘네트워킹’</u>을 해보고 싶어서 참석하게 되었다.</p><p>필자는 작년에 영어공부 플랫폼을 통해 실리콘밸리에 초청받아 구글, 우버, 메타 등 다양한 기업들을 투어해봤는데, <u>점심/저녁을 먹거나 심지어 쉬는 시간일 때조차 실리콘밸리 개발자들은 매우 열정적으로 어떤 주제에 대해 토론</u>하는 모습이 참 인상 깊었기 때문이다.</p><p>그 당시 언젠가는 대화하겠지라며 사람들에게 특별히 말을 걸지는 않고 넘어갔는데, <a href="https://www.oss.kr/open_up_intro">OpenUp</a>에서 최대 250만원까지 컨퍼런스 지원을 해준 덕에 1년 뒤인 지금 바로 꿈을 이루게 되었다 (?!)</p><p>참고로 이번에 참여한 컨퍼런스 이름은 바로 <a href="https://techsummit.tech/san-francisco/">Tech Summit Silicon Valley</a> 였다.</p><img src="./1.png" width="500"><br><h2 id="실리콘밸리에-갈-때-참고할-점"><a href="#실리콘밸리에-갈-때-참고할-점" class="headerlink" title="실리콘밸리에 갈 때 참고할 점"></a>실리콘밸리에 갈 때 참고할 점</h2><p>원래 후기를 컨퍼런스 내용에 대해서만 적으려고 했으나, 컨퍼런스 장소가 <u>외국 + 시골</u>인 점을 감안해서 한 번 작성을 해보도록 한다.<br>실리콘밸리에 가게 된다면 아래 내용을 참고하자.</p><ul><li>실리콘밸리 = 깡시골<ul><li>물론 우리나라 시골에 비해 버스와 지하철이 잘 되어 있으나, 결국 시골은 시골이다. 하물며 도시 대중교통도 잘 연착되는 편인데, 시골이면 오죽할까 (…)<br>돈 아끼려고 대중교통 이용하다가 오히려 약속에 늦는 비상사태가 벌어질 수 있다.</li><li>게다가 “미국”의 시골이다. 미국 땅덩어리와 우리나라를 비교하면 절대 안된다. 미국은 모든 곳이 차가 없으면 돌아다니기가 참 힘들다. 차로 10분인 거리가 도보로는 1시간이 걸리는 곳이다.</li><li>될 수 있으면 샌프란시스코 국제공항에서 내리자마자 렌트카를 빌리자. 생각보다 싸다. 그리고 미국의 교통 법규는 우리나라와 거의 동일하다.<ul><li>“비보호 좌회전, STOP표지판, 스쿨버스”가 가장 큰 차이점인데, 이거는 유튜브 영상 몇 개 보면 쉽게 이해할 수 있다.</li><li>도로가 매우 넓으며, (고속도로에 한해) 속도 제한도 한국보다 너그러운 편이라 쉽게 적응할 수 있다.</li><li>이 때 구글 지도로 네비게이션을 이용하면 된다.</li></ul></li></ul></li><li>미국 동부보다 영어에 대한 거부감이 적은 편<ul><li>필자의 개인적인 생각이다만, 능력있는 사람들이 모여있는 곳이다보니 영어권이 아닌 사람들이 많다.</li><li>그만큼 다양한 영어 발음을 구사해 서로의 영어를 못알아듣는 경우가 많다. 그래서 영어로 어떻게든 대화를 하려고 한다면 (동부보다 비교적) 상대방을 더욱 존중하고 이해하려는 모습을 보여준다.</li><li>영어에 두려움을 갖지 말고 자신이 무슨 말을 하고싶은지 어필하자. 다들 열심히 들어주고 얘기해줄 것이다.</li></ul></li></ul><p>그 외 나머지는 인터넷에 “미국 여행”같은 키워드를 검색해서 찾아보면 될 것이다.</p><p><br><br><br></p><p>서두는 이렇게 마무리하고, 본격적으로 컨퍼런스 후기를 작성해보도록 하겠다.<br>이번 포스트에서는 6월 19일에 진행된 컨퍼런스 내용을 바탕으로 작성해봤다.</p><img src="./2.jpeg" width="300"><p><del>막상 글 작성하니 이 사진 넣을 곳이 없어서 여기다가 낑겨본다</del></p><hr><h2 id="1-Using-technology-as-a-way-to-enable-financial-inclusion-in-emerging-markets"><a href="#1-Using-technology-as-a-way-to-enable-financial-inclusion-in-emerging-markets" class="headerlink" title="1. Using technology as a way to enable financial inclusion in emerging markets"></a>1. Using technology as a way to enable financial inclusion in emerging markets</h2><img src="./4.png" width="500">원래 AI/DB쪽으로 들으려다가 해당 강연들이 변경/취소되어 시간이 비어 고민하다가 들어보게 되었다.<p>스마트폰으로 배달, 주차, 학습 등 모든 것을 할 수 있는 시대가 되었으며, 은행업무도 디지털화가 많이 가속되었다며 2025년에는 3.7 trilion만큼의 시장 규모를 예측하고 있다는 내용이었다.</p><p>브라질의 76%, 페루의 63%, 멕시코의 71%, 칠레의 81%들이 디지털뱅크를 사용하고 있다는 연구결과도 보고, 이쪽 분야 초심자로서 내용을 쉽게 풀이해줘서 재밌게 들었다.</p><p>여기는 QnA가 재밌었는데, 인상이 깊어서 한 번 남겨본다.</p><ul><li>Q) 이러한 정보는 어떻게 찾았는가?<br>A) MasterCard, Visa 등에서 연구를 활용한 것이며, 정부에서도 해당 데이터를 종합해서 앞으로의 시장이 어떻게 변화할 것인지 예측하고 있음. 스터디도 찾아보면 많음</li><li>Q) 아메리카에서 최근 대두되고 있는 전략은?<br>A) Cash Free, Bank Transfer를 해결하는 방향으로 전략을 잡고 있다</li><li>Q) 앞으로 디지털뱅크쪽으로 산업이 확장될 것 같은가?<br>A) 전형적인 종이통장은 송금하는데 불편한 점이 많으며, 디지털뱅크는 이 단점을 전부 해결하기 때문에 결국에는 시장을 다 먹을 거긴 할거다. 그게 언젠지는 모르겠지만</li></ul><h2 id="2-WORKSHOP-Unlocking-Growth-AI-Driven-Strategies-Beyond-Metrics-and-Manuals"><a href="#2-WORKSHOP-Unlocking-Growth-AI-Driven-Strategies-Beyond-Metrics-and-Manuals" class="headerlink" title="2. WORKSHOP: Unlocking Growth: AI-Driven Strategies Beyond Metrics and Manuals"></a>2. WORKSHOP: Unlocking Growth: AI-Driven Strategies Beyond Metrics and Manuals</h2><img src="./6.png" width="500">이 분은 교수님인데, AI에 대해서 좀 더 집중적으로 세션을 진행했다.<p>최근 암호화 작업부터 전부 컴퓨터에 의존하고 있는 상황이기 때문에, AI가 결국에는 모든 일을 다 할거다는 얘기와 최근에는 자동화 쪽으로 크게 관심을 받고 있는 상황이라 이 시장을 유의하라고 했다.<br>또한 최근 AI + 오픈소스의 발전으로 개발이 쉬워졌기 때문에 비전공자라도 한 번 개발에 도전을 해볼만하다는 내용이 있었다.</p><p>여기서는 이 내용을 크게 강조했다.</p><ul><li>Identify your key workflows</li><li>Experiment with different ai tools</li><li>Create replicable prompts</li><li>Measure and iterate</li></ul><h2 id="3-PANEL-SESSION-Exploring-the-Power-of-Artificial-Intelligence"><a href="#3-PANEL-SESSION-Exploring-the-Power-of-Artificial-Intelligence" class="headerlink" title="3. PANEL SESSION: Exploring the Power of Artificial Intelligence"></a>3. PANEL SESSION: Exploring the Power of Artificial Intelligence</h2><img src="./3.png" width="500"><p>여기서도 AI가 주제인 만큼, 최근 AI업계의 핫이슈 ChatGPT에 대해 길게 토론하는 시간을 가졌다.<br>내 생각과 동일하게 “간단한 것에 대해서는 사용이 용이하나, C레벨의 임원직인 경우에는 의사결정이 필요할 때 사용을 주의해야 한다”는 내용이었다.</p><p>두 번째로는 AI 학습에 관해서도 얘기를 나눴는데, 인공지능 개발에 있어서도 결국 데이터의 organization이 중요하다며 체계적으로 분류하는 방법에 대해서 연구해야한다고 대화를 나눴다.<br>그리고 데이터를 체계적으로 나누는 것은 결국 자동화가 들어가게 될텐데, 개발자든 비개발자든 이쪽으로도 관심을 가지면 좋을 것이라고 이야기가 와갔다.</p><p>마지막으로 AI개발자의 동향에 관한 토론도 이루어졌는데, 임원직들에게는 “AI개발자를 바로 채용하지 말고 ChatGPT나 Llama3같은 걸 먼저 사용해볼 것. BM 스케일이 커질 때 고용을 고려하라”,<br>개발자에게는 “채용 시장이 동결된 만큼 보수적으로 접근해야 한다. 따라서 AI개발자가 되려면 degree를 못해도 석사까지는 해놓는게 좋을 것 같다”라는 내용으로 정리할 수 있을 것 같다.</p><h2 id="4-PANEL-SESSION-Data-Driven-Innovation"><a href="#4-PANEL-SESSION-Data-Driven-Innovation" class="headerlink" title="4. PANEL SESSION: Data-Driven Innovation"></a>4. PANEL SESSION: Data-Driven Innovation</h2><img src="./5.png" width="500"><p>여기서는 데이터에 관해서 좀 더 자세하게 패널들이 대화를 나누는 세션이었다.</p><p>최근의 데이터는 고객을 이해시키기 위해 사용되는 것이며, “보안, 정확성”에 대한 어필이 좀 더 필요하고<br>기술을 발달로 인해 프레임워크와의 결합이 쉽고 데이터엔지니어들이 파이프라인을 쉽게 구축할 수 있어 무조건적으로 데이터퀄리티를 증가시켜야 한다는 내용이었다.</p><p>다만 체계적으로 정리하는 습관을 기를거면 수학 공부는 무조건적으로 추천하며, AI에 관심이 있다면 언어 모델 플랫폼이 2년 사이에 많이 발전했기 때문에 퀄리티는 툴마다 다르겠지만 개발은 쉬울 것이라는 얘기가 나왔다.</p><p>결론적으로는 데이터에 대한 “보안, 정확성”에 대해서 정부 규제까지 강화될 것으로 보이기 때문에<br>데이터 모델 리펙토링은 매우 조심해야 한다는 내용이 있었다.</p><p>오픈소스를 기업에서도 사용할텐데, 이 점에서는 오픈소스 개발자들도 유의해야겠는 생각이 들었다.</p><h2 id="1일차-후기"><a href="#1일차-후기" class="headerlink" title="1일차 후기"></a>1일차 후기</h2><ul><li><p>일단 개발자 중심의 컨퍼런스가 아니기 때문에, 컨퍼런스 내용은 일반인들도 이해하기 쉽게끔 구성이 되어 있었다.<br>근데 실리콘밸리 특성답게 결국은 개발자들끼리 자발적으로 모여서 추가로 의견을 나누는 시간을 가질 수 있어서 컨퍼런스가 재미있었던 것 같다.<br>다들 따스웠던게, 요즘 트랜드 파악 겸 오픈소스 개발하는데 좀 도움되는 정보 있나 싶어 한국에서 비행기타고 와서 참가했다고 얘기하니까<br>비행기 타고 오느라 힘들었겠다며 음식을 이것 저것 잘 챙겨줬다. 영어도 잘한다고 칭찬해주고.. <del>토종한국인은 감동의 눈물을 흘렸어요</del></p><p>아래는 대화 내용을 요약한 것이다.</p><ul><li>오픈소스에 대해서는 다른 나라에서도 생태계를 키우려고 노력한다고 한다. 듣기로는 프랑스(였던걸로 기억하는데 정확하지는 않고.. 일단 유럽 어딘가)는 올해의 오픈소스를 매년 선정하여 해당 메인 컨트리뷰터에게 상금을 준다고 한다. 외국인도 돈을 준다고 하던데 한 번 관심 있으면 찾아보라고 하더라</li><li>최근 이슈였던 Redis에 대해서도 열띤 토론을 했는데, 다들 이번 사태로 오픈소스 생태계가 어느 정도 수축되었다며 아쉬어하는 목소리를 냈다.</li><li>당연히 AI와 데이터베이스에 대해서도 대화를 나눴다. 여기서도 동일하게 AI든 데이터베이스든 일단 organization이 제대로 되야 관리면에서, 학습면에서 모두 좋은 결과물을 얻을 수 있다고 얘기했다.<br>그 외 평소에 궁금했던 것들(ex. 데이터베이스에 로컬시간 저장 관련)을 물어봤는데, 다들 사람인지라 의견이 다들 다르더라. 근데 얘기를 들어보면 정리 스타일만 다를 뿐 데이터를 체계적으로 정리한 것은 동일했기에 모두 들어볼 만 했다.<br>그것보다 대화를 나누는데 서로 의견을 존중하면서 의견 어필하는게 인상 깊었다. 여기는 말하는 것부터도 되게 전문적으로 하는 느낌이랄까.</li><li>취직 면에서는… 미국 시장은 아직도 매우 차갑다고 한다.<br>실제로 나를 마음에 들어했던 빅테크 기업 개발자는 시장이 어느정도 괜찮으면 나보고 여기서 일하자고 추천하고 싶은데, 여기가 너무 살얼음판이다보니 지금 직장에 계속 다니는게 안전해 보인다며 아쉬워하더라. (실리콘밸리 자체가 쉽게 취직되고 잘리는 곳이라지만, 요즘 정리해고는 쉽고 취직/이직이 어려워졌다고 한숨을 쉬는 건 덤)<br>개인적인 생각이다만 미국이 한국 시장의 1년 뒤라고 생각하고 보는 편인데, 아직도 여기가 얼음장인거 보면 취직 시장이 참 춥구나 싶은 생각이 든다 ㅠㅠ</li></ul></li></ul><ul><li><p>원래 이날 듣고 싶었던 컨퍼런스 주제가</p><ul><li>AI translation & language accessibility</li><li>Business Models Innovation using AI Technology Workshop</li></ul><p>였으나, 아쉽게도 해당 주제는 변경/취소되어 참석하지 못했다. 특히 NLP쪽으로 관심이 많았는데 좀 많이 아쉽더라 🥲</p></li><li><p>왜인지 모르겠으나 앞에 빈자리가 많음에도 불구하고 뒤에서 서서 듣는 사람들이 많았다. 중간에 나갈려고 그런가 싶었는데, 그건 또 아닌 것 같았다. 대부분 들어와서 끝까지 듣더라. 여기 문화가 그런건지, 아니면 앞에 앉아서 주목받기 싫어서 그런건지는 아직도 미스테리 ㅎㅎ;;</p></li></ul>]]></content>
<categories>
<category> ✈️ Conference </category>
</categories>
<tags>
<tag> Conference </tag>
</tags>
</entry>
<entry>
<title>[TIPS] Python, Javascript 프로젝트에서 유용한 regex 문법 및 관련 패키지 모음집</title>
<link href="/2022/11/25/Tips/Regex/"/>
<url>/2022/11/25/Tips/Regex/</url>
<content type="html"><![CDATA[<p>사용자의 입력값이 유효한지 확인하는 작업을 해야할 때가 있는데, 이 때 사용하면 유용한 패키지와 각종 regex를 정리해봤습니다.</p><p>(상시 업데이트 예정)</p><h2 id="Python3"><a href="#Python3" class="headerlink" title="Python3"></a>Python3</h2><hr><ul><li><a href="https://pydantic-docs.helpmanual.io/">pydantic</a></li></ul><br><h3 id="Email-Validation"><a href="#Email-Validation" class="headerlink" title="- Email Validation"></a>- Email Validation</h3><ul><li><p>RFC-5322 표준 기준</p> <pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> reEMAIL_REGEX <span class="token operator">=</span> <span class="token string">r"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*\")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))g"</span><span class="token keyword">return</span> re<span class="token punctuation">.</span>fullmatch<span class="token punctuation">(</span>EMAIL_REGEX<span class="token punctuation">,</span> email<span class="token punctuation">)</span> <span class="token comment"># True or False</span></code></pre></li></ul><h3 id="Name-Validation"><a href="#Name-Validation" class="headerlink" title="- Name Validation"></a>- Name Validation</h3><ul><li>letter(a-z, A-Z), apostrophe, hyphen 지원</li><li>여기서는 최소 길이 1 및 최대 길이 20인 문자열만 유효한 것으로 판단 <pre class="language-python" data-language="python"><code class="language-python"><span class="token keyword">import</span> reNAME_REGEX <span class="token operator">=</span> <span class="token string">r"(^[aA-zZ '-]{1,20})"</span><span class="token keyword">return</span> re<span class="token punctuation">.</span>fullmatch<span class="token punctuation">(</span>NAME_REGEX<span class="token punctuation">,</span> name<span class="token punctuation">)</span> <span class="token comment"># True or False</span></code></pre></li></ul><p><br><br><br></p><h2 id="Javascript"><a href="#Javascript" class="headerlink" title="Javascript"></a>Javascript</h2><hr><ul><li><a href="https://github.com/jquense/yup">yup</a>: 주로 <a href="https://formik.org/">formik</a>과 합쳐서 사용한다</li></ul><br><h3 id="Email-Validation-1"><a href="#Email-Validation-1" class="headerlink" title="- Email Validation"></a>- Email Validation</h3><ul><li>RFC-5322 표준 기준 <pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token constant">EMAIL_REGEX</span> <span class="token operator">=</span> <span class="token regex"><span class="token regex-delimiter">/</span><span class="token regex-source language-regex">^[-a-z0-9!#$%&'*+/=?^_`{|}~]+(\.[-a-z0-9!#$%&'*+/=?^_`{|}~]+)*@([a-z0-9_][-a-z0-9_]*(\.[-a-z0-9_]+)*\.(aero|arpa|biz|com|coop|edu|gov|info|int|mil|museum|name|net|org|pro|travel|mobi|[a-z][a-z])|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}))(:[0-9]{1,5})?$</span><span class="token regex-delimiter">/</span><span class="token regex-flags">i</span></span><span class="token punctuation">;</span><span class="token keyword">const</span> ex1 <span class="token operator">=</span> <span class="token string">"I can do it"</span><span class="token punctuation">;</span><span class="token keyword">const</span> ex2 <span class="token operator">=</span> <span class="token string">"my.email@address.com"</span><span class="token punctuation">;</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>ex1<span class="token punctuation">.</span><span class="token function">match</span><span class="token punctuation">(</span><span class="token constant">EMAIL_REGEX</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// false</span>console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span>ex2<span class="token punctuation">.</span><span class="token function">match</span><span class="token punctuation">(</span><span class="token constant">EMAIL_REGEX</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment">// true</span></code></pre></li></ul>]]></content>
<categories>
<category> 💾 Etc </category>
</categories>
<tags>
<tag> Python3 </tag>
<tag> Regex </tag>
<tag> Javascript </tag>
</tags>
</entry>
<entry>
<title>네트워크 기본</title>
<link href="/2022/05/30/NS/Basic/"/>
<url>/2022/05/30/NS/Basic/</url>
<content type="html"><![CDATA[<h2 id="IPv4"><a href="#IPv4" class="headerlink" title="IPv4"></a>IPv4</h2><hr><ul><li>컴퓨터 사이에 통신을 하기 위해서는 컴퓨터 위치값을 알아야 함</li><li>이때 각 컴퓨터의 <code>위치값(주소)</code> IP 주소라고 지칭함 (IP Version 4)</li><li>점<code>.</code> 사이의 숫자들은 옥텟(octet)이라고 부름</li></ul><h4 id="IPv4-클래스"><a href="#IPv4-클래스" class="headerlink" title="IPv4 클래스"></a>IPv4 클래스</h4><ul><li>첫 번째 옥탯의 앞자리에 따라 클래스 구분</li><li>주로 A, B class 사용<ul><li><strong>A Class</strong>: 첫 번째 옥탯의 맨 앞자리 비트가 0<ul><li>8bit의 네트워크 bit + 24bit의 호스트 bit</li><li>즉 1개의 네트워크가 2^24개의 ip를 보유</li><li>이러한 네트워크가 2^7개만큼 있음 (식별자 제외)</li><li>대규모 프로젝트에 적합: 국가 단위</li></ul></li><li><strong>B Class</strong>: 첫 번째 옥탯의 앞 두자리의 비트가 1, 0<ul><li>16bit의 네트워크 bit + 16bit의 호스트 bit</li><li>즉 1개의 네트워크가 2^16개의 ip를 보유</li><li>이러한 네트워크가 2^14개만큼 있음 (식별자 제외)</li></ul></li><li><strong>C Class</strong>: 첫 번째 옥탯의 앞 세자리의 비트가 1, 1, 0<ul><li>24bit의 네트워크 bit + 8bit의 호스트 bit</li><li>즉 1개의 네트워크가 2^8개의 ip를 보유</li><li>이러한 네트워크가 2^21개만큼 있음 (식별자 제외)</li><li>소규모 프로젝트에 적합</li></ul></li></ul></li></ul><p><br><br></p><h2 id="Subnet-Sub-Network"><a href="#Subnet-Sub-Network" class="headerlink" title="Subnet: Sub + Network"></a>Subnet: Sub + Network</h2><hr><ul><li>한 사람이 하나의 네트워크를 소유 시 IP가 모자름 -> 모자른 IP를 방지하기 위해 네트워크를 분할하는 개념</li><li>빨간색 부분의 숫자만 바뀌는 것을 확인할 수 있음</li><li>이를 간편하게 표기하기<ul><li><code>[그룹에서 맨 앞의 ip주소/32bit 중 그대로인 부분 개수]</code>로 표기</li><li>subnet A: 211.11.124.0/25</li><li>subnet B: 211.11.124.128/25</li></ul></li></ul><p><br><br></p>]]></content>
<categories>
<category> 🔐 Network/Security </category>
</categories>
<tags>
<tag> Network </tag>
<tag> IP </tag>
<tag> Subnet </tag>
</tags>
</entry>
<entry>
<title>Windows & Mac에서 nvm 설치하기 (Node.js, Npm, Yarn 설치)</title>
<link href="/2022/05/17/Etc/Windows-Mac-Osx-Nvm-Install/"/>
<url>/2022/05/17/Etc/Windows-Mac-Osx-Nvm-Install/</url>
<content type="html"><![CDATA[<p>개발 프로젝트에 따라서 Node의 버전을 여러 개 설치하고 번갈아 사용해야 하는 경우가 있는데,<br>이럴 때는 nvm(Node Version Manager)를 사용하면 여러 개의 node 버전을 설치하여 원하는 node 버전을 골라서 사용할 수 있다.</p><br><h2 id="설치-시-사전-주의-사항"><a href="#설치-시-사전-주의-사항" class="headerlink" title="설치 시 사전 주의 사항"></a>설치 시 사전 주의 사항</h2><ul><li>기존에 Node가 설치되어 있다면 Node를 제거해야 한다.</li><li>글은 업로드한 날짜 그대로 있지만, node는 프로그램으로 계속 끊임없이 업데이트되며 발전한다.<br>글에 나와있는 버전 그대로 따라 치는 것보다는 <strong>자신이 사용할 버전을 직접 고르고 설치할 것</strong>을 추천한다.<br>설치할 수 있는 node 버전 리스트는 여기서 참고하면 된다: <a href="https://nodejs.org/ko/download/releases/">https://nodejs.org/ko/download/releases/</a></li></ul><p><br><br></p><h2 id="Windows에서-설치하기"><a href="#Windows에서-설치하기" class="headerlink" title="Windows에서 설치하기"></a>Windows에서 설치하기</h2><ol><li><a href="https://github.com/coreybutler/nvm-windows/releases">nvm-windows repository</a>에 접속하여 release된 파일을 다운받는다. 이 때 파일유형이 <code>.zip</code>인 것을 다운받는다.<img src="/2022/05/17/Etc/Windows-Mac-Osx-Nvm-Install/1.png" class="" title="nvm-windows repository 다운로드"></li></ol><br><ol start="2"><li>압축을 풀면 폴더 내부에 <code>nvm-setup.exe</code> 파일이 있는데, 해당 파일을 실행하면 nvm이 설치된다.<img src="/2022/05/17/Etc/Windows-Mac-Osx-Nvm-Install/2.png" class="" title="nvm-setup.exe 파일"></li></ol><br><ol start="3"><li>윈도우 터미널에서 아래 명령어들을 통해 node를 버전별로 설치 및 관리, 사용을 할 수 있다.<pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># nvm 버전 확인</span>nvm version<span class="token comment"># 설치된 node 리스트</span>nvm <span class="token function">ls</span><span class="token comment"># node 버전별 설치하기</span>nvm <span class="token function">install</span> <span class="token number">14.17</span>.6<span class="token comment"># nvm에서 특정 node 버전 활성화하기</span>nvm use <span class="token number">15.11</span>.0<span class="token comment"># npm으로 yarn 설치하기</span><span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">-g</span> <span class="token function">yarn</span></code></pre></li></ol><p><br><br></p><h2 id="Mac에서-설치하기"><a href="#Mac에서-설치하기" class="headerlink" title="Mac에서 설치하기"></a>Mac에서 설치하기</h2><ul><li><p>nvm repository: <a href="https://github.com/nvm-sh/nvm">https://github.com/nvm-sh/nvm</a></p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># nvm 설치하기</span><span class="token function">curl</span> -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.11/install.sh <span class="token operator">|</span> <span class="token function">bash</span><span class="token comment"># node 버전별 설치하기</span>nvm <span class="token function">install</span> <span class="token number">14.17</span>.3<span class="token comment"># nvm에서 특정 node 버전 활성화하기</span>nvm use <span class="token number">15.11</span>.0<span class="token comment"># npm으로 yarn 설치하기</span><span class="token function">npm</span> <span class="token function">install</span> <span class="token parameter variable">-g</span> <span class="token function">yarn</span></code></pre></li><li><p>만약에 nvm을 설치하고 확인했을 때 <code>command not found</code>가 나오면 <code>bash_profile</code>을 확인하자.</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">vi</span> ~/.bash_profile<span class="token comment"># 아래의 코드 확인. 오타나 누락 시 직접 수정</span><span class="token builtin class-name">export</span> <span class="token assign-left variable">NVM_DIR</span><span class="token operator">=</span><span class="token string">"<span class="token environment constant">$HOME</span>/.nvm"</span><span class="token punctuation">[</span> <span class="token parameter variable">-s</span> <span class="token string">"<span class="token variable">$NVM_DIR</span>/nvm.sh"</span> <span class="token punctuation">]</span> <span class="token operator">&&</span> <span class="token builtin class-name">.</span> <span class="token string">"<span class="token variable">$NVM_DIR</span>/nvm.sh"</span> <span class="token comment"># This loads nvm</span><span class="token comment"># 재시작</span><span class="token builtin class-name">source</span> ~/.bash_profile</code></pre></li></ul>]]></content>
<categories>
<category> 💾 Etc </category>
</categories>
<tags>
<tag> Node.js </tag>
<tag> Npm </tag>
<tag> Yarn </tag>
<tag> Nvm </tag>
</tags>
</entry>
<entry>
<title>DevOps 개요</title>
<link href="/2022/05/12/DevOps/Intro/"/>
<url>/2022/05/12/DevOps/Intro/</url>
<content type="html"><![CDATA[<h2 id="1-DevOps-정의"><a href="#1-DevOps-정의" class="headerlink" title="1. DevOps 정의"></a>1. DevOps 정의</h2><hr><blockquote><p>“A set of practices intended to reduce the time between commiting a change to a system and the change being placed into normal production, while ensuring high quality”</p><p>제품의 변경사항을 품질을 보장함과 동시에 프로덕션에 반영하는데 걸리는 시간을 단축하기 위한 실천 방법의 모음</p></blockquote><ul><li>개발(Dev)와 운영(Ops)의 합성어</li><li>개발과 운영의 경계를 허물과 하나의 팀으로 통합하고자 하는 문화 또는 철학</li><li>개발과 운영의 벽을 허물어 더 빨리 자주 배포하는 것</li></ul><p><br><br></p><h2 id="2-DevOps가-필요한-이유"><a href="#2-DevOps가-필요한-이유" class="headerlink" title="2. DevOps가 필요한 이유"></a>2. DevOps가 필요한 이유</h2><hr><ul><li>조직의 규모가 커지면 각 단계 별 전문가로 구성된 기능 조직을 운영할 수 있음</li><li>그만큼 의사소통이 많아지기 때문에 커뮤니케이션의 문제가 발생</li><li>개발자가 SW 생애주기 중 여러 단계에 참여한다면 이러한 문제를 해결할 수 있음</li></ul><ul><li>넷플릭스에서 제안하는 <strong>Full-cycle Developer</strong></li><li>SW 개발 생애주기의 전체에 직접 참여하는 개발자</li></ul>]]></content>
<categories>
<category> ♼ DevOps </category>
</categories>
<tags>
<tag> DevOps </tag>
</tags>
</entry>
<entry>
<title>대학생 때 알았다면 좋았을 SW 팁</title>
<link href="/2022/05/10/Retrospect/Bachelor/"/>
<url>/2022/05/10/Retrospect/Bachelor/</url>
<content type="html"><![CDATA[<p>SW분야를 선택하고 스펙을 쌓으며 가장 고생했던 것 중 하나가 바로 <strong>조언해주는 사람이 없다는 것</strong>이었다.</p><p>어떤 분야든 멘토가 있다면 효율적으로 스펙을 쌓고 빠르게 기술을 습득할 수 있겠지만, 주변에 컴퓨터 분야에 종사하는 사람이 눈 씻고봐도 전혀 없었다.<br>심지어 대학교 자체를 나온 사람이 주변에 친언니(문과 전공) 하나밖에 없었기에, 혼자서 익스트림 칠전팔기 도전기를 찍었던 것 같다.</p><p>나같은 사람이 더 이상 없길 바라며, 나름 생각하는 꿀팁들을 적어보려고 한다.</p><blockquote><p>추가적으로 궁금한 내용 있으시면 언제든지 편하게 댓글 남겨주세요 :-)</p></blockquote><p><br><br></p><h2 id="언어-선택"><a href="#언어-선택" class="headerlink" title="언어 선택"></a>언어 선택</h2><p>본인이 하고 싶은 분야의 언어를 선택한다. 딱히 하고 싶은 분야가 없다면 제일 무난한 <code>Java</code>를 추천한다. 취업시장 자체가 서버 개발자 수요가 많은데, 그 중 전반적으로 가장 많이 구하는 기술 스택이 바로 <code>Java</code>이기 때문이다.<br>다만 스타트업을 노리고 있다면 <code>Javascript</code>, <code>Python</code>을 추천한다. 최근 스타트업들이 이 두 언어를 주요 기술 스택으로 선택하는 추세다.</p><p>코딩 테스트 언어로는 무난하게 <code>C/C++</code>, <code>Python</code>을 추천한다. 다른 언어를 선택해도 관계없다. 자신이 가장 자신있는 언어를 선택하는 것이 좋다.<br>주변에서 종종 시간초과 문제 때문에 <code>Python</code>을 망설이는 경우가 있는데, 시간초과 문제는 나중에 해결할 일이다. 일단 돌아가는 코드를 만들어야 부분점수라도 얻을 수 있지 않겠는가.</p><p>사실 학부생 수준에서 언어 선택은 크게 중요하지 않다. 왜냐면 취직해봤자 온보딩만 평균 1개월-3개월 정도 돌리는데 그러면 일은 커녕 공부만 주구장창 하고있기 때문이다.<br>(카카오 다니는 지인 왈, <strong>입사한지 5개월 됐는데 일 하나도 안하고 공부만 했어…</strong> <del>물경력</del>)<br>그래서 학부생 시절에 될 수 있으면 다양한 수업을 접하면서 여러 언어들을 익혀보는 것을 추천한다.<br>다만 분야마다 주력으로 하는 언어가 있기 때문에, 특정 분야를 가기로 결심했으면 그 언어는 공부해놓는게 좋다.</p><table> <tbody><tr> <td><b>분야</b></td> <td><b>언어</b></td> </tr> <tr> <td>AI/빅데이터</td> <td>Python</td> </tr> <tr> <td>서버</td> <td>Java</td> </tr> <tr> <td>프론트엔드</td> <td>Javascript</td> </tr> <tr> <td>하드웨어/임베디드</td> <td>C, C++</td> </tr></tbody></table><p><br><br></p><h2 id="졸업-전-반드시-들어야-할-전공-과목"><a href="#졸업-전-반드시-들어야-할-전공-과목" class="headerlink" title="졸업 전 반드시 들어야 할 전공 과목"></a>졸업 전 반드시 들어야 할 전공 과목</h2><ul><li>자료구조</li><li>알고리즘</li><li>데이터베이스</li><li>네트워크</li><li>운영체제</li></ul><p>대부분 기업들이 <code>코딩테스트 > 면접</code> 과정을 거치는데, 먼저 코딩테스트는 대부분 자료구조, 알고리즘 문제가 출제된다.<br>면접에서는 데이터베이스, 네트워크, 운영체제에 관련해 질문이 따발총으로 들어오므로 꼭 수강해놓는 것을 추천한다.<br>이 과목들 중 하나라도 공부를 안하고 취뽀에 도전한다면 현실적으로 많이 힘들다.</p><p><br><br></p><h2 id="비전공자-개발자"><a href="#비전공자-개발자" class="headerlink" title="비전공자 개발자"></a>비전공자 개발자</h2><p>컴퓨터공학이 만만한 학문은 아니지만, 분야 특성 상 인터넷에 수많은 지료들이 존재하며 자료 공유가 활발한 편이다.<br>유튜브, 카카오톡 오픈톡방, 그 외 다양한 커뮤니티들 및 사이트에서 원하는 정보를 쉽게 찾을 수 있다.</p><p>그래도 적성이 안맞으면 굉장히 괴로운 분야이기 때문에 대학생이라면 프로그래밍 과목을 한 번 들어보고, 아니라면 인터넷 자료들을 통해 공부를 해보는 것을 추천한다.</p><p><br><br></p><h2 id="학교-비전공자-메리트"><a href="#학교-비전공자-메리트" class="headerlink" title="학교 / 비전공자 메리트"></a>학교 / 비전공자 메리트</h2><p>어떤 곳이든 기본적으로 학벌을 보기에 여기 또한 학벌의 존재를 피해갈 순 없다. 다만 다른 분야에 비하면 개발 자체는 학교 학과를 안 보는 직군으로 평가된다.<br>따라서 학교 네임밸류와 컴퓨터 외 전공 때문에 취업이 안된다고 말하는 사람들은 ‘내가 과연 열심히 살았나?’라며 솔직하게 자기반성의 시간을 가져야 한다. 정말 노력만 한다면 커버가 될 수 있기 때문이다.</p><blockquote><p>그럼에도 불구하고 나는 안된다 하시는 분들, 경쟁자들과 비빌 수 있는 스펙을 만들기 위해 부던히 노력을 하셨습니까? 남들이 놀 때 정말 잠도 안자고 공부하셨나요? 가슴에 손을 얹고 한 번 생각해보시길 바랍니다.</p></blockquote><p>비전공자들에 관련해서 추가적인 조언을 해보자면, 비전공자가 뽑히지 않는 이유는 <code>전공자와 비교했을 때 그만한 경험과 지식이 부족하다고 판단</code>되기 때문이다. 대부분의 비전공자들이 부트캠프나 국비지원으로 개발공부를 하는데, 이 모든 과정들이 길어봤자 1년이기 때문에 현실적으로도 4년제 전공생들과 비교되는건 당연하다.</p><p>그래도 개발 스펙을 쌓고자 한다면 개인적으로 추천하는 것은 <code>부트캠프</code>이다.<br>이미 개발자들 사이에서 <strong>국비지원 = 개발자 찍어대는 공장 -> 국비지원 출신 = 코딩 대충 배운 사람</strong>으로 인식하는 경우가 많기 때문이다. (좆소기업을 유심히 살펴보면 국비지원 출신이 많은 경우를 찾을 수 있다)</p><p>다음은 그 중 추천하는 부트캠프 프로그램이다.</p><ul><li><a href="https://woowacourse.github.io/">우아한 테크코스 (우테코)</a></li><li><a href="https://boostcamp.connect.or.kr/">BoostCamp (부스트캠프 / 부캠)</a></li><li><a href="https://www.swmaestro.org/sw/main/main.do">SW마에스트로(소마)</a></li><li><a href="https://42seoul.kr/seoul42/main/view">42SEOUL</a>: 프랑스의 유명 프로그램인 42Ecole을 벤치마킹한 대한민국 정부 지원 SW 개발자 양성 프로그램이다. 전 세계적으로 유명한 프로그램인 만큼 회사 지원했을 때 도움되는 경우가 많다.</li><li><a href="https://www.ssafy.com/">Ssafy(싸피)</a>: 삼성에서 지원하는 SW 개발자 양성 프로그램이다. 졸예자 이상만 참가 가능하다.</li></ul><p>국비지원을 선택했더라도 자신의 노력에 달렸으니 더더욱 열심히 CS공부를 하는 것을 추천한다.</p><p><br><br></p><h2 id="개발자로-지원할-수-있는-기업"><a href="#개발자로-지원할-수-있는-기업" class="headerlink" title="개발자로 지원할 수 있는 기업"></a>개발자로 지원할 수 있는 기업</h2><p>크게 두 가지로 나뉜다.<br>(금융권 IT 등 다양하게 있겠지만 이 쪽으로는 잘 몰라서 패스)</p><ul><li><strong>대기업 IT 자회사</strong>: LG CNS, 현대오토에버, 삼성 SDS 등<ul><li>그룹 계열사의 IT 서비스를 개발 및 운영</li><li>흔히 대기업 SI로 불리며, 취업 시장에서 가장 많이 채용</li><li>장점: 높은 연봉과 안정성</li><li>단점: 수직적인 기업문화, 개발 기회가 적음(대체로 운영 업무 위주)</li></ul></li><li><strong>IT 서비스 기업</strong>: 네카라쿠배(네이버, 카카오, 라인, 쿠팡, 배달의 민족)<ul><li>개발적인 측면에서 자유를 보장받을 수 있으며 다양한 기회 또한 접할 수 있음</li><li>계속 개발 공부를 하면서 성장하고 싶다면 추천</li><li>장점: 자유로운 기업문화</li><li>단점: 평생 공부, 기업별 연봉차가 매우 큼(대기업 vs 스타트업), 안정성 보장 못함</li></ul></li></ul>]]></content>
<categories>
<category> 🎈 Retrospect </category>
</categories>
<tags>
<tag> Retrospect </tag>
<tag> Job </tag>
<tag> 42SEOUL </tag>
</tags>
</entry>
<entry>
<title>[MSA] Micro Service Architecture: Outer - Service Mesh</title>
<link href="/2022/04/30/Architecture/MSA-outer-service-mesh/"/>
<url>/2022/04/30/Architecture/MSA-outer-service-mesh/</url>
<content type="html"><![CDATA[<p>MSA의 Outer Architecture 중 Service Mesh에 대해 알아보자.</p><p><br><br></p><h2 id="MSA-개념-설명-읽어보기"><a href="#MSA-개념-설명-읽어보기" class="headerlink" title="MSA 개념 설명 읽어보기"></a>MSA 개념 설명 읽어보기</h2><hr><ul><li><a href="/2022/04/26/Architecture/MSA-Intro/" title="[MSA] Micro Service Architecture 개요">[MSA] Micro Service Architecture 개요</a></li></ul><p><br><br></p><h2 id="Service-Mesh"><a href="#Service-Mesh" class="headerlink" title="Service Mesh"></a>Service Mesh</h2><hr><ul><li>마크크로서비스 간의 통신(네트워크)을 제어하는 역할<ul><li>통신 및 네트워크 기능을 비즈니스 로직과 분리한 네트워크 통신 인프라</li><li>모든 서비스의 인프라 layer로 서비스들 간의 통신 처리</li></ul></li><li>service discovery, service routing, load balancing(트래픽 관리) 및 보안 등을 담당함</li></ul><p><br><br></p><h2 id="API-Gateway와의-차이점"><a href="#API-Gateway와의-차이점" class="headerlink" title="API Gateway와의 차이점"></a>API Gateway와의 차이점</h2><hr><p>먼저 <a href="/2022/04/28/Architecture/MSA-outer-gateway/" title="[MSA] Micro Service Architecture: Outer - External Gateway">[MSA] Micro Service Architecture: Outer - External Gateway</a>를 읽고 아래 표를 보는 것을 추천한다.</p><ul><li>최근 MSA에서 다음과 같이 사용:</li><li>API Gateway는 노출되는 부분(External)에 위치하며 내부서비스를 보호 및 제어하는 역할로 사용</li><li>Service Mesh는 내부 서비스(Internal)에 위치하여 서비스를 관리하는 구조로 사용</li></ul> <table> <tbody><tr> <td></td> <td>API Management</td> <td>Service Mesh</td> </tr> <tr> <td><b>적용되는 위치</b></td> <td>마이크로서비스 그룹의 외부 경계에 위치하여 역할 수행</td> <td>경계 내부에서 역할 수행</td> </tr> <tr> <td><b>아키텍쳐 형태</b></td> <td>중앙집중형 아키텍쳐 = SPOF(Single Point of Failure) 생성</td> <td>분산형 아키텍쳐 = SPOF를 생성하지 않고 확장이 용이</td> </tr> <tr> <td><b>패턴</b></td> <td>- Gateway proxy pattern 사용<br>- Consumer(호출자)가 구현 내용을 알 필요없이 Gateway를 호출하는 방법만 알면 Gateway가 알아서 수행해주는 방식</td> <td>- Sidecar proxy pattern 사용<br>- Consumer(호출자)의 코드에 Provider(공급자)의 주소를 찾는 방법, failover와 관련된 코드 등의 내용이 들어가게 설정<br>- 호출자의 코드는 어플리케이션 코드(비즈니스 로직)에 내장되지 x, sidecar 형태로 별개로 관리됨</td> </tr> <tr> <td>라우팅 주체</td> <td>서버</td> <td>요청하는 서비스</td> </tr> <tr> <td>라우팅 구성요소</td> <td>별도의 네티워크를 도입하는 독립적인 API gateway 구성 요소</td> <td>서비스 내 sidecar로 Local network 스택의 일부가 됨</td> </tr> <tr> <td>로드 밸런싱</td> <td>- 단일 엔드포인트를 제공<br>- API Gateway 내 로드밸런싱을 담당하는 구성요소에 요청을 redirection하여 해당 구성 요소가 처리함</td> <td>- Service Registry에서 서비스 목록을 수신함<br>- sidecar에서 로드밸런싱 알고리즘을 통해 수행함</td> </tr> <tr> <td>네트워크</td> <td>외부 인터넷과 내부 서비스 네트워크 사이</td> <td>- 내부 서비스 네트워크 사이 <br> - 응용 프로그램의 네트워크 경계 내에서만 통신이 가능하게 함</td> </tr> <tr> <td>분석</td> <td>API에 대한 사용자 및 공급자에 대한 모든 호출에 대해 수집되고 분석</td> <td>Mesh 내 모든 마이크로서비스 구성요소에 대해 분석</td> </tr></tbody></table><p><br><br></p><h2 id="Service-Mesh의-종류"><a href="#Service-Mesh의-종류" class="headerlink" title="Service Mesh의 종류"></a>Service Mesh의 종류</h2><hr><h4 id="PaaS-Platform-as-a-Service-의-일부로-서비스-코드에-포함되는-유형"><a href="#PaaS-Platform-as-a-Service-의-일부로-서비스-코드에-포함되는-유형" class="headerlink" title="PaaS (Platform as a Service)의 일부로 서비스 코드에 포함되는 유형"></a>PaaS (Platform as a Service)의 일부로 서비스 코드에 포함되는 유형</h4><ul><li>Microsoft Azure Service fabric, lagom, SENECA</li><li>프레임워크 기반의 프로그래밍 모델 -> service mesh를 구현하는데 특화한 코드가 필요함(Mesh-native Code)</li></ul><h4 id="라이브러리로-구현되어-API-호출을-통해-Service-mesh에-결합되는-유형"><a href="#라이브러리로-구현되어-API-호출을-통해-Service-mesh에-결합되는-유형" class="headerlink" title="라이브러리로 구현되어 API 호출을 통해 Service mesh에 결합되는 유형"></a>라이브러리로 구현되어 API 호출을 통해 Service mesh에 결합되는 유형</h4><ul><li>Spring Cloud, Netflix OSS(Ribon/Hystrix/Eureka/Archaius), finagle</li><li>프레임워크 라이브러리를 사용<ul><li>Netflix의 Prana는 sidecar 형태로 동작함</li></ul></li><li>Service mesh를 이해하고 코드를 작성해야 함 (Mesh Aware Code)</li></ul><h4 id="Sidecar-proxy를-이용하여-Service-mesh를-마이크로서비스에-주입하는-유형"><a href="#Sidecar-proxy를-이용하여-Service-mesh를-마이크로서비스에-주입하는-유형" class="headerlink" title="Sidecar proxy를 이용하여 Service mesh를 마이크로서비스에 주입하는 유형"></a>Sidecar proxy를 이용하여 Service mesh를 마이크로서비스에 주입하는 유형</h4><ul><li>Istio/Envoy, Consul, Linkerd</li><li>sidecar proxy 형태로 동작</li><li>service mesh와 무관하게 코드 작성<blockquote><p><b>sidecar pattern</b></p><ul><li>컨테이너 배포방식의 경우 모든 응용 프로그램 컨테이너에 추가로 sidecar 컨테이너가 배포됨</li><li>서비스에 들어오거나 나가는 모든 네트워크 트래픽을 처리</li><li>비즈니스 로직이 포함된 실제 서비스와 sidecar가 병렬로 구성됨 = 서비스 호출에서 proxy를 통해 호출(서비스가 직접 서비스 호출x)</li><li>대규모 마이크로서비스 환경이여도 개발자가 별도의 작업 없이 서비스의 연결, 로깅, 모니터링, 보안, 트래픽 제어를 할 수 있음</li><li>최근 Service Mesh에서 Sidecar pattern 유형을 많이 사용하는 추세</li></ul></blockquote></li></ul><p><br><br></p><h2 id="Service-Mesh의-주요-기능"><a href="#Service-Mesh의-주요-기능" class="headerlink" title="Service Mesh의 주요 기능"></a>Service Mesh의 주요 기능</h2><hr><p>일반적으로 Istio나 consul, Linkerd와 같은 Service Mesh 프레임워크들에서 기능 지원</p><ul><li>Service Discovery</li><li>Load balancing (지연시간 기반 / 대기열 기반)</li><li>Dynamic Request Routing</li><li>Circuit Breaking</li><li>암호화 (TLS)</li><li>보안</li><li>Health check, Retry and Timeout</li><li>Metric 수집</li></ul>]]></content>
<categories>
<category> 🔧 Architecture </category>
</categories>
<tags>
<tag> MSA </tag>
<tag> Architecture </tag>
<tag> API </tag>
<tag> ESB </tag>
<tag> Sidecar </tag>
</tags>
</entry>
<entry>
<title>[MSA] Micro Service Architecture: Outer - External Gateway</title>
<link href="/2022/04/28/Architecture/MSA-outer-gateway/"/>
<url>/2022/04/28/Architecture/MSA-outer-gateway/</url>
<content type="html"><![CDATA[<p>MSA의 Outer Architecture 중 External Gateway에 대해 알아보자.</p><p><br><br></p><h2 id="MSA-개념-설명-읽어보기"><a href="#MSA-개념-설명-읽어보기" class="headerlink" title="MSA 개념 설명 읽어보기"></a>MSA 개념 설명 읽어보기</h2><hr><ul><li><a href="/2022/04/26/Architecture/MSA-Intro/" title="[MSA] Micro Service Architecture 개요">[MSA] Micro Service Architecture 개요</a></li></ul><p><br><br></p><h2 id="External-Gateway"><a href="#External-Gateway" class="headerlink" title="External Gateway"></a>External Gateway</h2><hr><img src="/2022/04/28/Architecture/MSA-outer-gateway/1.png" class="" title="MSA External Gateway 구조"><ul><li>전체 서비스 외부로부터 들어오는 접근을 내부 구조를 드러내지 않고 처리하기 위한 요소</li><li>사용자 인증 (Consumer Identity Provider)과 권한 정책관리(Policy Management)를 수행</li><li><code>API Gateway</code>가 가장 핵심적인 역할</li></ul><p><br><br></p><h2 id="API-Gateway"><a href="#API-Gateway" class="headerlink" title="API Gateway"></a>API Gateway</h2><hr><ul><li>서버 최앞단에 위치하여 모든 API 호출을 받음 (API 서버들의 endpoint 단일화를 해주는 또다른 서버)</li><li>API에 대한 인증과 인가 기능을 가지고 있음: 받은 API 호출을 인증한 후, 적절한 서비스들에 메세지를 전달(routing)</li><li>SOA의 핵심 인프라인 <code>ESB</code>(Enterprise Service Bus)에서 비롯됨<ul><li>EBS는 SOAP/XML 기반의 무거운 기능</li><li>API Gateway는 REST/JSON 기반의 가벼운 기능</li></ul></li></ul><p><br><br></p><h2 id="API-Gateway의-주요-기능"><a href="#API-Gateway의-주요-기능" class="headerlink" title="API Gateway의 주요 기능"></a>API Gateway의 주요 기능</h2><hr><ol><li><strong>인증 및 인가</strong> (Authentication and Authorization)<ul><li>MSA에서 각각의 서비스에 API호출에 대한 인증 및 인가를 한다는 것 = 같은 소스코드를 서비스 인스턴스들마다 심어줘야 함 = 소스의 중복이 심하여 유지 관리가 어렵고, 로깅 모니터링을 관리하는 것도 매우 어려워짐</li><li>따라서 인증서 관리나 인증, SSL, 프로토콜 변환화 같은 기능들을 API Gateway에서 오프로드 -> 각각의 서비스 부담 줄이기 및 서비스 관리, 업그레이드가 용이함<blockquote><p>Authentication (인증) vs Authorization (인가)</p><ul><li>Authentication: 유저가 누구인지 확인하는 절차</li><li>Authorizatoin: 어떠한 유저가 특정 자원에 접근하려 할 때, 그에 대한 접근 권한이 있는지 확인하는 절차</li></ul></blockquote></li></ul></li><li><strong>요청 절차의 단순화</strong><ul><li>API Gateway가 없을 시 클라이언트에 여러 서비스들에 대한 요청을 진행해야 함</li><li>API Gateway는 여러 클라이언트의 요청을 단일 클라이언트의 요청으로 대체 가능하도록 만들어줌</li><li>따라서 클라이언트와 백엔드 간 APU 통신량이 줄어 대기시간이 줄어줄이고 효율성을 높일 수 있음</li></ul></li><li><strong>라우팅 및 로드밸런싱</strong><ul><li>클라이언트로부터 접수된 메시지에 따라, API 호출을 적절한 서비스에 라우팅</li><li>서비스 인스턴스들에 대한 부하분산 가능</li></ul></li><li><strong>서비스 오케스트레이션</strong><ul><li><code>오케스트레이션</code>: 여러 개의 마이크로 서비스를 묶어 새로우 서비스를 만드는 개념</li><li>과도한 오케스트레이션 로직: APU Gateway의 부담을 늘리는 것 = 성능 저하</li></ul></li><li><strong>서비스 디스커버리</strong><ul><li>API Gateway는 각 서비스 호출을 위해 서비스마다 IP주소 및 포트번호를 알고 있어야 함</li><li>lagacy 환경에서는 크게 문제될 점이 없지만, 클라우드 환경에서는 <code>동적</code>으로 배포되기 때문에 서비스 위치를 찾는 것이 어려움<ul><li>이러한 서비스의 위치를 찾는 것을 <code>Service Discory</code></li></ul></li><li>서버 사이드나 클라이언트 사이드를 기준으로 서비스 디스커버리 구현 가능</li></ul></li></ol><p><br><br></p><h2 id="API-Gateway-적용-시-고려사항"><a href="#API-Gateway-적용-시-고려사항" class="headerlink" title="API Gateway 적용 시 고려사항"></a>API Gateway 적용 시 고려사항</h2><hr><ul><li><p>API Gateway 계층이 추가적으로 만들어진다는 의미 = 그 만큼 네트워크 latency 증가</p></li><li><p>API Gateway의 Scale-out 적용이 유연하게 일어나지 않을 경우, API Gateway가 병목지점이 되어 어플리케이션의 성능저하가 일어날 수 있음</p></li><li><p>API Gateway의 가장 큰 단점은 <code>API Gateway를 내부 마이크로서비스와 결합한다는 것</code><br>-> 기존 SOA에서의 EBS(Enterprise Service Bus)에서 발생했던 문제점이 다시 발생할 수 있음</p><blockquote><p>2000년대 후반, 많은 SOA 프로젝트가 실패한 이유로 SOA의 핵심적인 요소 중 하나인 ESB가 꼽히는 경우가 많음.</p><ul><li>당시 EBS 내부 처리 로직을 XML 기반으로 했는데, XML의 파싱은 오버헤드가 큰 작업</li><li>EBS는 가벼운 연산 외에도 과도한 Orchestration 등 무거운 로직을 가짐. 대부분 ESB를 Gateway로의 특성이 아닌 시스템을 통합하기 위한 역할로 많이 구현했음</li></ul></blockquote></li></ul>]]></content>
<categories>
<category> 🔧 Architecture </category>
</categories>
<tags>
<tag> MSA </tag>
<tag> Architecture </tag>
<tag> API </tag>
<tag> ESB </tag>
</tags>
</entry>
<entry>
<title>[MSA] Micro Service Architecture 개요</title>
<link href="/2022/04/26/Architecture/MSA-Intro/"/>
<url>/2022/04/26/Architecture/MSA-Intro/</url>
<content type="html"><![CDATA[<p>요즘 핫이슈로 개발자라면 무조건 알아야 할 개념인 MSA에 적어보고자 한다.</p><h2 id="MSA의-등장배경-모놀리식-아키텍처-Monolithic-Architecture"><a href="#MSA의-등장배경-모놀리식-아키텍처-Monolithic-Architecture" class="headerlink" title="MSA의 등장배경: 모놀리식 아키텍처 (Monolithic Architecture)"></a>MSA의 등장배경: 모놀리식 아키텍처 (Monolithic Architecture)</h2><hr><img src="/2022/04/26/Architecture/MSA-Intro/1.png" class="" title="모놀리식 아키텍처 구조"><ul><li>소프트웨어의 모든 구성 요소가 한 프로젝트에 통합되어있는 형태<ul><li>쉽게 학교에서 프로젝트할 때를 생각하면 됨<ul><li>소규모 프로젝트에서 합리적: 간단한 architecture, 용이한 유지보수</li></ul></li></ul></li><li>수백명의 개발자가 투입되는 프로젝트같은, <strong>일정 규모 이상의 서비스</strong>를 운영할 때 한계가 있음<ul><li>서비스, 프로젝트가 커지면 커질수록 영향도 파악 및 전체 시스템 구조 파악에 어려움이 있음</li><li>빌드 시간 및 테스트 시간, 배포 시간이 기하급수적으로 늘어남</li><li>서비스를 부분적으로 scale-out하기 힘듦</li><li>부분의 장애가 전체 서비스의 장애로 이어질 수 있음</li></ul></li></ul><p><br><br></p><h2 id="Micro-Service-뜻"><a href="#Micro-Service-뜻" class="headerlink" title="Micro Service 뜻"></a>Micro Service 뜻</h2><hr><img src="/2022/04/26/Architecture/MSA-Intro/2.png" class="" title="마이크로서비스 아키텍처 개념"><blockquote><p>“the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery.”</p></blockquote><p>출처: <a href="https://martinfowler.com/articles/microservices.html">https://martinfowler.com/articles/microservices.html</a></p><ul><li><strong>small services, each running in its own process</strong>: 스스로 돌아갈 수 있는 작은 서비스</li><li><strong>independently deployable</strong>: 독립적 배포 가능</li><li>각각의 서비스는<ul><li>매우 작은 단위로 구성되어 있지만 서비스 자체는 하나의 MA(모놀리틱 아키텍처)와 유사 구조를 지님</li><li>독립적으로 배포 가능</li><li>다른 서비스에 대한 의존성이 최소화 되어야 함</li><li>개별 프로세스로 구동되며, REST와 같은 가벼운 방식으로 통신되어야 함</li></ul></li></ul><p><br><br></p><h2 id="MSA의-장점"><a href="#MSA의-장점" class="headerlink" title="MSA의 장점"></a>MSA의 장점</h2><hr><ul><li>배포(Deployment) 관점: 서비스 별 개별 배포 가능 (배포 시 전체 서비스 중단이 없음) -> 요구사항을 신속하게 반영하여 빠르게 배포할 수 있음</li><li>확장(Scaling) 관점: 특정 서비스에 대한 확장성이 용이 -> 클라우드 사용에 적합한 아키텍처</li><li>장애(Failure) 관점: 장애가 전체 서비스로 확장될 가능성이 적음 -> 부분적 장애에 대한 격리가 수월함</li><li>신기술의 적용이 유연하며, 서비스를 polyglot하게 개발/운영할 수 있음</li></ul><p><br><br></p><h2 id="MSA의-단점"><a href="#MSA의-단점" class="headerlink" title="MSA의 단점"></a>MSA의 단점</h2><hr><ul><li>Monolithic Architecture보다 복잡한 아키텍처 -> 전체 서비스가 커질수록 그 복잡도는 기하급수적으로 늘어남</li><li>성능: 서비스 간 호출 시 API를 사용함 -> 통신 비용 및 latency(지연 시간)이 그만큼 늘어남</li><li>테스트/트랜잭션: 서비스가 분리되어 있음 -> 테스트와 트랜잭션 복잡도 증가, 많은 자원을 요구</li><li>데이터 관리: 데이터가 여러 서비스에 걸쳐 분산되기 때문에 한 번에 조회화기 어렵고, 데이터의 정합성 또한 관리가 힘듦</li></ul><p><br><br></p><h2 id="MSA-구조"><a href="#MSA-구조" class="headerlink" title="MSA 구조"></a>MSA 구조</h2><hr><img src="/2022/04/26/Architecture/MSA-Intro/3.png" class="" title="MSA 전체 구조"><ol><li><strong>Inner Architecture</strong> (남색 부분): 내부 서비스와 관련된 아키텍처<ul><li>고려사항<ul><li>마이크로 서비스를 어떻게 정의할 것인가?</li><li>DB Access 구조를 어떻게 설계할 것인가?</li><li>마이크로 서비스 내 api를 어떻게 설계할 것인가?</li><li>논리적인 컴포넌트들의 layer를 어떠한 방식으로 설계할 것인가?</li></ul></li><li>표준이 없어 MSA를 설계하는데 가장 어려운 부분</li></ul></li><li><strong>Outer Architecture</strong> (회색 부분)<ul><li><a href="/2022/04/28/Architecture/MSA-outer-gateway/" title="[MSA] Micro Service Architecture: Outer - External Gateway">[MSA] Micro Service Architecture: Outer - External Gateway</a></li><li><a href="/2022/04/30/Architecture/MSA-outer-service-mesh/" title="[MSA] Micro Service Architecture: Outer - Service Mesh">[MSA] Micro Service Architecture: Outer - Service Mesh</a></li><li>Container Management</li><li>Backing Services</li><li>Telemetry</li><li>CI/CD Automation</li></ul></li></ol>]]></content>
<categories>
<category> 🔧 Architecture </category>
</categories>
<tags>
<tag> MSA </tag>
<tag> Architecture </tag>
</tags>
</entry>
<entry>
<title>[후기] 스타트업/중소기업/대기업 인턴 및 정규직 준비 과정</title>
<link href="/2022/04/23/Retrospect/Junior/"/>
<url>/2022/04/23/Retrospect/Junior/</url>
<content type="html"><![CDATA[<h2 id="1-👩🏻💻-내가-개발자…"><a href="#1-👩🏻💻-내가-개발자…" class="headerlink" title="1. 👩🏻💻 내가 개발자…?"></a>1. 👩🏻💻 내가 개발자…?</h2><p>대입준비를 하면서도 컴퓨터는 단 1도 생각하지 않았지만 현실부정을 하기엔 이미 대학교 등록까지 마쳐버렸다.<br>결론적으로 소프트웨어학과에 입학했으니 한 번 해보자며 도전했는데 글쎄, 다들 한 번에 합격하던 학교 c언어 인증시험을 2번이나 낙방했다.</p><p>이 때 컴퓨터에 대한 재능이 그렇게 뛰어나지 않은걸 깨달아 다른 길을 찾으려 했지만 바늘 구멍보다 더 좁은, 취업이 힘든 이 시국에 내가 배운거라곤 컴퓨터밖에 없어 결국 개발자의 길을 반강제적으로 선택하게 됐다.<br><code>개발자로 취직한다</code>라고 내 자신을 납득시키고 인정하도록 만드는게 가장 어려웠던 것 같다.</p><p><br><br></p><h2 id="2-🎯-세부-진로-선택-스펙-쌓기-대외활동"><a href="#2-🎯-세부-진로-선택-스펙-쌓기-대외활동" class="headerlink" title="2. 🎯 세부 진로 선택 + 스펙 쌓기 = 대외활동"></a>2. 🎯 세부 진로 선택 + 스펙 쌓기 = 대외활동</h2><p>개발자로 목표를 잡았으니 풀스택, 안드로이드, 데이터사이언스 등 세부 진로를 잡아야 하는데 컴퓨터 분야가 너무 넓어 도저히 선택을 할 수 없었다.<br>그나마 재능 있는 분야로 가야할 것 같은데 배울 내용이 너무나도 많았고, 가뜩이나 머리도 좋은 편이 아닌데 아르바이트 + 학교(21학점) 병행으로 온전히 학습에 집중하기 어려운 환경이었다.<br>그래서 효율적인 학습방안을 고안했는데 그게 바로 <code>대외활동</code>이였다.</p><h4 id="왜-대외활동"><a href="#왜-대외활동" class="headerlink" title="왜 대외활동?"></a>왜 대외활동?</h4><p>돈 없는 학생 입장에서 무언가를 무료로 배울 수 있다는 것, 가끔은 활동비도 준다는게 매우 긍정적으로 보였다.<br>그리고 대학생이 되었으니 그 때만 받을 수 있는 혜택 최대한 다 받아봐야 하지 않겠는가 싶었다.</p><h4 id="대외활동-종류"><a href="#대외활동-종류" class="headerlink" title="대외활동 종류"></a>대외활동 종류</h4><ul><li>제주코딩베이스캠프 10기 (2019년 상반기) <a href="https://blog.naver.com/dev_rubykim/222449187535">책1</a> <a href="https://blog.naver.com/dev_rubykim/222449183632">책2</a><br>3년에 한번 들어갈까 말까하는 페이스북 계정이 있는데, 갑자기 생각나 잠시 들어갔더니 친구 한 명이 제주코딩베이스캠프에 좋아요 표시를 남긴게 피드에 뜨면서 자연스레 알게 되었다.<br>아무것도 없는 스펙이라 진심을 담아 지원서를 썼더니 운좋게 합격했다. (뭔지는 모르겠지만 1장 썼는데 합격했다. 반면 10장 넘게 쓴 사람은 떨어졌다고 한다. 운영진 말로는 지원이유에 포커싱을 잘 맞춘 지원자를 뽑았다던데 내껀… 잘 모르겠다.)<br>가서 파이썬 자동화 수업을 들으며 이왕 잡은 기회 틈틈히 엿보다가 운 좋게 책 2권을 공동집필 및 출판했다.</li><li><a href="https://blog.naver.com/dev_rubykim/222457413201">네이버 BOOSTER</a> (2019년 하반기)<br>네이버의 부스트코스를 수강하던 중, 부스트 코스 홍보대사를 뽑는다는 공지를 보고 지원했다.<br>당시 블로그 운영에 집중하고 있던터라 일방문자가 100명 정도 됐는데 그 덕에 합격한 것 같다.<br>덕분에 안드로이드 코스를 수강하며 무료로 전문가 첨삭을 받을 수 있었다. 1회에 3만 5천원 정도였던 걸로 기억하는데 홍보대사로서 대차게 잘 활용했던 대외활동이다.</li><li><a href="https://blog.naver.com/dev_rubykim/222457399153">HUFS IT</a> (2020년 하반기)<br>이 프로그램은 취준생 + 창업을 위한 사람을 뽑는 곳이다. 처음에는 3학년이라는 이유로 떨어졌는데, 4학년에 다시 지원하니 붙었다. 인공지능과 블록체인에 대한 수업을 들었는데 전부 이론관련 내용이었다. 여담으로 중간에 자소서 첨삭 등도 봐주셨는데 유익했던 것 같다.</li><li><a href="https://blog.naver.com/PostList.naver?blogId=dev_rubykim&from=postList&categoryNo=23">대코캠(대학교 코딩 캠프) 서포터즈 1기</a> (2021년 하반기)<br>당시 코드잇에서 DB 강의를 들었는데 지금까지 들었던 수업 중 가장 쉽고 머리에 쏙쏙 박히는 설명에 열심히 수업을 수강하던 중이었다. 수강 만료 기간이 다가와 아쉬워하던 차 대코캠 서포터즈를 하면 추가 수강권을 준다고 하여 지원했고, 덕분에 수강권을 받아 추가로 수업을 더 들을 수 있었다.</li><li><a href="https://blog.naver.com/PostList.naver?blogId=dev_rubykim&from=postList&categoryNo=39">JE코베 서포터JU 2기</a> (2021년 하반기)<br>제주코딩베이스캠프에서 주최하는 서포터즈 활동으로, 제코베에서 만든 강의들을 모두 무료로 제공해준다 하여 지원하고 열심히 수강했다. 여기서 Django 수업을 많이 수강했다.</li></ul><h4 id="대외활동-합격팁"><a href="#대외활동-합격팁" class="headerlink" title="대외활동 합격팁"></a>대외활동 합격팁</h4><ol><li><p>대부분의 대외활동들은 자기 기업 PR을 위해 진행한다.<br>따라서 효과적인 기업홍보를 할 수 있는 방안을 미리 만들어놓는 것이 좋다.</p><ul><li><a href="https://blog.naver.com/dev_rubykim">블로그</a>: 보통 대외활동은 블로그를 통해 프로그램 관련 포스팅을 진행한다.</li><li><a href="https://www.youtube.com/channel/UCbOmJzYjQAxdtuJdPI0f9Sg">유튜브</a>: 개발 관련 대외활동으로는 거의 쓰이지 않는다.</li><li><a href="https://www.instagram.com/rubyhae_/">인스타그램</a>: 보통 카드뉴스 형식으로 진행된다.</li></ul><p>플랫폼에 상관없이, 미리 약간의 콘텐츠를 업로드하여 어느 정도의 방문자를 만들어 놓는 것이 관건이다.</p></li><li><p>각 대외활동에서 중요시 보는 부분 파악하기<br>각각의 기업마다 중요시 하는 부분이 다르다.<br><strong>봉사</strong>같이 남에게 선한 영향력을 끼칠 수 있는가, 아니면 <strong>취업</strong>이나 <strong>창업</strong>에 관심이 있는가 등 다양한 조건을 가지고 지원자의 합불을 결정한다.<br>이는 주최사의 회사이념이나 창업자의 가치관을 보고 쉽게 판단할 수 있는데, 보통 인터넷에 검색하면 자료들을 찾을 수 있으니 이것저것 한 번 검색해보는걸 추천한다. 대외활동 사이트에 있는 사람들의 후기들을 통해서도 살펴볼 수 있다.</p></li></ol><h4 id="대외활동-사이트-추천"><a href="#대외활동-사이트-추천" class="headerlink" title="대외활동 사이트 추천"></a>대외활동 사이트 추천</h4><p>여러 대외활동 사이트가 있는데, 대부분의 대외활동 사이트에 동일한 내용이 올라오기 때문에 사이트는 하나만 추천하려고 한다.</p><ul><li><a href="https://allforyoung.com/">요즘것들</a><br>시중에 나와있는 대외활동 사이트 중 가장 깔끔한 UI로 구성됐다.</li><li><a href="https://github.com/ruby-kim/Realtime-IT-Contest-notification">공모전 & 대외활동 알림 repository</a><br>42SEOUL을 하면서 잠깐 사람들 모아 진행했던 프로젝트다. 3일에 1번 대외활동 사이트를 크롤링하여 issue를 자동 open/close하도록 설정했다.</li></ul><h4 id="그-외-스펙을-위한-활동"><a href="#그-외-스펙을-위한-활동" class="headerlink" title="그 외 스펙을 위한 활동"></a>그 외 스펙을 위한 활동</h4><p>이왕 쓰는거 오직 스펙 쌓기를 위해 참가했던 프로그램 및 대회에 관해서도 적어본다.</p><ol><li>학교 연구실 인턴 (2019년 상반기)<br>이왕 대학생이 된거 대학원 비스무리한 생활도 해보고파 방법을 찾던 중 학교에서 연구실 인턴을 뽑는다는 공고문을 보고 지원했다.<br>교수님과 면접을 봤는데 좋게 봐주셔서 인턴으로 들어갔다. 그런데 인턴이라 그런가 너무 프리하게 놔주시더라.<br>뭔가 교수님이 하라는대로 하는데, 결과물을 내놓아도 그에 맞는 페이나 결과 등.. 내게 남는 것이 전혀 없어서 결국 나왔다.</li><li>고교 SW멘토링 (2019년 상반기)<br>바쁠 것 같아서 처음에는 안하려고 했는데 친구의 권유로 참가했다. 여름방학에 2주 정도 고등학교에 방문해서 파이썬을 가르쳤다.</li><li>학교 교내 SW/AI 해커톤 (2018년 하반기 / 2019년 상반기 / 2020년 상반기)<br>맨 처음 해커톤은 아무것도 모르는 상태에서 야식 공짜로 먹으러 참가한거라 아무 소득없이 1차에서 바로 탈락했다.<br>나머지 해커톤에서는 상을 받았는데, 먼저 2019년도 해커톤은 당시 인공지능 프로젝트에서 사용했던 모델 그대로 사용해도 괜찮겠다는 생각이 들어 참가했고 운 좋게 상을 수상했다.<br>그 다음해에는 서로 합이 맞은 친구들과 같이 해커톤에 참가하여 수상했다.</li><li><a href="https://blog.naver.com/dev_rubykim/222457473353">2019년도 K-SW Purdue Program</a> (2019년 하반기)<br>정부 지원으로 전공공부와 더불어 외국생활을 할 수 있다는 것에 감명받아 열심히 준비했다. (원래 외국에서 일해보고자 하는 꿈을 갖고 있었다.)<br>당시 OPIc 성적이 IL과 IM1을 받을 만큼 그닥 좋지 않아 영어 면접 질문 답변 리스트를 빽빽이로 5장 정도 준비했던게 기억난다.</li><li><a href="https://blog.naver.com/dev_rubykim/222454922801">42SEOUL</a> (2020년 하반기)<br>온보딩 신청은 2019년 11월에 바로 했는데, 당시 K-SW Purdue Program으로 외국에 있어 일부러 2기로 신청했다. 원래라면 2020년 3월 즈음에 라피신을 진행해야 했지만, 코로나로 인해 연장이 되면서 7월부터 라피신을 진행했다. 최종합격 이후, 9월부터 본격적으로 42SEOUL 본과정에 합류해 프로젝트를 진행했다.</li></ol><p><br><br></p><h2 id="3-🌸-스펙의-꽃-인턴에-도전-정규직까지"><a href="#3-🌸-스펙의-꽃-인턴에-도전-정규직까지" class="headerlink" title="3. 🌸 스펙의 꽃, 인턴에 도전 + 정규직까지!"></a>3. 🌸 스펙의 꽃, 인턴에 도전 + 정규직까지!</h2><p>이렇게 대외활동들을 통해 어느 정도 기술을 습득했다. 하지만 학생과 직장인에게는 엄연히 큰 차이가 있다.<br>그 차이를 어느 정도 극복을 해놔야 나중에 취준할 때 도움이 될 것 같아서, 그리고 어떤 분야로 갈지 확실히 정하기위해 경험삼아 인턴십에 도전했다.</p><p><del>사실대로 말하면 학교가기 싫어서 인턴 도전했다. 제발 졸업시켜주세요</del></p><p>참고로 스타트업은 맨 앞 첫 글자만 작성했다.ㅎㅎ</p><h4 id="Google-Korea-인턴-2019년-하반기-불합격"><a href="#Google-Korea-인턴-2019년-하반기-불합격" class="headerlink" title="Google Korea 인턴 (2019년 하반기): 불합격"></a>Google Korea 인턴 (2019년 하반기): 불합격</h4><p>당시 K-SW Purdue Program으로 미국에 있었는데, 경험삼아 도전해볼까?하며 했던게 면접까지 진출해버렸다(…)<br>포지션은 <code>안드로이드 개발자</code>였는데, 큰 이유는 없고 인턴 지원 당시 네이버 BOOSTER로 활동하며 공부했던 안드로이드가 내 최신 기술이었기 때문이다.</p><p>1차 코딩테스트 이후 서류를 가지고 합불을 가렸는데 코테결과가 나름 처참했음에도 서류가 좋아서 그런가 합격했다.<br>코딩테스트는 <a href="https://codingcompetitions.withgoogle.com/kickstart">Kick Start</a>에서 진행했는데, 알고리즘 보다는 무지성 + 노가다로 문제를 풀었다.</p><img src="/2022/04/23/Retrospect/Junior/1.png" class="" title="Google Korea 인턴 코딩테스트 결과"><p>이후로는 1차 면접날, 면접관님과 ‘안녕하세요’와 ‘소리 잘 들리시죠?’ 이 두 마디 이후 바로 면접이 시작됐다.<br>소문으로만 들었던 외국계 면접이 이런거구나 체감했던 것 같다. 면접관님은 시종일관 면접에 관련된 질문만 던지시고 내 스펙, 성적 등 전부 관심이 없으셨다.</p><p>1차 면접은 거의 <code>2차 코딩테스트</code>였다. 특정한 자료 구조를 주며 구글 Docs에 직접 구현해보는 것이었는데, 솔직히 이런 문제가 나올줄 몰랐고 무엇보다 면접이 영어로 진행됐기 때문에 어버버 하면서 면접에 임했다. 당시 영어라곤 OPIc IM1이 다인, 자유롭게 영어로 얘기를 전혀 못하는 사람이었다. 그 때문인가 2차에서 결국 탈락했다.</p><p>기술면접이 끝나고 주니어 개발자로서 궁금한 내용이 있으면 물어보라는 얘기에 이런저런 얘기를 했는데, 좋은 말씀을 많이 해주셔서 도움이 됐던 것 같다. 여담으로 구글 코리아 지하의 운동시설이 그렇게 좋다는 정보를 얻었다.</p><h4 id="Naver-Clova-인턴-2019년-하반기-불합격"><a href="#Naver-Clova-인턴-2019년-하반기-불합격" class="headerlink" title="Naver Clova 인턴 (2019년 하반기): 불합격"></a>Naver Clova 인턴 (2019년 하반기): 불합격</h4><p>이 또한 K-SW Purdue Program으로 미국에 있을 때 갑자기 지원했던 인턴십이다.<br>당시 멘토님을 뵙고자 팀원들과 시카고로 갔는데, 교수님께서 카톡으로 네이버 클로바 인턴으로 추천해줄테니 한 번 지원해보지 않겠냐며 권유를 하셨다.<br>좋은 기회인 것 같아 급작스럽지만 서류와 포트폴리오를 열심히 준비했다. <del>그렇게 시카고 미술관 입구만 구경한 채 건너편 스타벅스에서 컴퓨터만 깔짝댔다.</del></p><p>당시 인공지능 관련 스펙이라곤 학교 프로젝트가 다였기에, 서류에서부터 떨어졌던 것 같다.</p><h4 id="스타트업-M사-인턴-2020년-상반기-불합격"><a href="#스타트업-M사-인턴-2020년-상반기-불합격" class="headerlink" title="스타트업 M사 인턴 (2020년 상반기): 불합격"></a>스타트업 M사 인턴 (2020년 상반기): 불합격</h4><p>뭔 바람이 불었는지 갑자기 인공지능에 꽂혀 <code>인공지능 개발자</code> 포지션으로 국내 인공지능 스타트업으로 유명한 M사에 지원했다.</p><p>웃기게도 코딩테스트는 5문제 중 1문제(심지어 그 1문제의 테스트 케이스를 전부 맞추지 못했다)를 맞췄는데, 서류와 포트폴리오가 너무 잘 되어있어 궁금하다 하셔서 반강제로 1차에서 합격했다.<br>코딩테스트를 못 본 이유가 있었다. <strong>다익스트라</strong> 같이 알고리즘 과목에 대한 깊은 지식이 있어야 풀 수 있는 문제가 출제됐는데, 당시 알고리즘을 아예 배우지 않은 상태에서 코딩테스트를 봤으니 점수가 처참했다.</p><p>면접에서는 추가적인 알고리즘 시험이 있었다. 파이썬 구현 문제였는데 정답이긴 하지만 10%정도? 부족한 답변을 내놓았다. 다만 다른 파이썬 문제는 의도대로 잘 풀었다.<br>다음으로는 프로젝트에 관한 면접이 진행됐고 차근히 잘 맞받아쳤던 것으로 기억한다.</p><p>다만 면접을 보시면서 자꾸 걱정하시던게 하나 있으셨는데, 바로 내가 그 당시 3학년 2학기를 준비하고 있었다는 것었다.<br>그 때문에 몇 번 망실이시는 모습을 보여주시더니 결국 최종에서 불합격을 받았다.</p><h4 id="스타트업-D사-인턴-2020년-상반기-합격"><a href="#스타트업-D사-인턴-2020년-상반기-합격" class="headerlink" title="스타트업 D사 인턴 (2020년 상반기): 합격"></a>스타트업 D사 인턴 (2020년 상반기): 합격</h4><p>이 회사는 <code>풀스택 엔지니어</code>로 지원했다. 위 M사와 동일하게 <code>인공지능 개발자</code>로 회사를 지원하고자 인터넷을 뒤졌는데, 인공지능 개발자로 4학년 이하의 학사를 뽑는 경우가 거의 없었다.<br>고민 끝에 <strong>인공지능 회사에 들어가서 어깨 너머로 배워야겠다</strong>라는 무대포 마음으로 무작정 인공지능 관련 회사에 아무 기술 포지션으로 지원했다.</p><p>전남에 있는 회사인데, 당시 코시국으로 뉴스가 난리났음에도 불구하고 직접 기차타고 오라 하길래 고민하다가 결국 비대면으로 면접을 봤다.<br>Django에서 손을 뗀지 1년이 넘어 아리까리했는데, 의외로 면접을 좋게 봤던 것 같다. 몇 문제는 제대로 답변을 못했지만 <strong>이런건 인턴으로 들어와서 다시 공부하면 되는거니까 걱정 마세요</strong>라며 <strong>인상 좋고 참 밝으시네요</strong>라며 시종일관 칭찬만 들었다.<br>지금이야 얘기하지만 사실 이 회사 면접은 형편없었다. 전부 알맹이가 빠진 질문들만 해왔기 때문이다.</p><p>위에 적었듯이 학교가기 싫어서 인턴을 지원했던터라 맨 처음에는 유일하게 합격한 여기로 인턴을 가고자 했지만, 바로 뒤에 후술할 회사 또한 합격해 이 회사는 결국 패스했다.</p><h4 id="중견기업-S사-인턴-2020년-상반기-합격"><a href="#중견기업-S사-인턴-2020년-상반기-합격" class="headerlink" title="중견기업 S사 인턴 (2020년 상반기): 합격"></a>중견기업 S사 인턴 (2020년 상반기): 합격</h4><p>최종적으로 2020년 상반기에서는 여기서 인턴십을 진행했다. <code>인공지능 개발자</code> 포지션의 인턴을 뽑길래 지원했고 코딩테스트도 5문제 중 4문제로 무난하게 풀었다.</p><p>그런데 면접을 갔더니 이미 실장님께서는 나를 인턴으로 내정하신 상태였다. 면접을 보러갔는데 시종일관 칭찬만 들었다. <strong>3학년인데 인공지능을 할 줄 알아요?</strong> <strong>포트폴리오 너무 잘 만들었네요. 3학년 맞아요?</strong> <strong>인사성도 좋고 인상도 좋고 아주 좋아요. 이번 인턴은 기대되는데요?</strong> 눈 앞에서 직격타로 칭찬을 들으니 낯간지럽고 그냥 그 자리를 벗어나고 싶다는 생각만 들었다.</p><p>회사는 음성인식 관련 인공지능을 개발하는 곳으로, 인터넷에 Open 음성인식 API를 찾아 돌아다니면 종종 볼 수 있는 곳이였다. 이 회사가 위 D사보다 규모도 더 크고, 무엇보다 인공지능을 배울 수 있다는 생각에 여기를 선택했다.</p><h4 id="외국계-기업-인턴-정규직-88개-1승-87패-2020년-하반기-2021년-하반기"><a href="#외국계-기업-인턴-정규직-88개-1승-87패-2020년-하반기-2021년-하반기" class="headerlink" title="외국계 기업 인턴 & 정규직 88개: 1승 87패 (2020년 하반기 - 2021년 하반기)"></a>외국계 기업 인턴 & 정규직 88개: 1승 87패 (2020년 하반기 - 2021년 하반기)</h4><p>주변 사람들에게 누누히 얘기했지만, 해외에서 바로 취직하고 싶다는 마음에 학교 졸업 프로젝트를 하면서 시간이 날 때마다 기업에 지원했다. (비자 때문에 일찍 지원하는게 맞다고 생각했다.)</p><p>원래 계획은 <code>ICT 프로젝트 인턴십 해외과정 합격</code> -> <code>실리콘밸리 입성</code> -> <code>정규직으로 전환 후 알박기</code>였는데, 맨 처음인 ICT 프로젝트 인턴십 학교 선발에서부터 불합격을 받아버렸다.<br>영어회화가 문제인 것 같아 하루에 6시간 이상을 혼자 영어로 떠들며 열심히 준비했더니, 2021년 하반기 과정 참여 대학 리스트 중 재학 중인 학교가 없어 결국 지원하지 못했다.</p><p>그래도 한 번 휴학을 한 탓에 내게는 4학년 2학기 과정이 남아있었고, 아직 졸업을 하지 않았으니 지금 이 순간에는 내가 하고 싶은대로 기업에 지원을 해보자며 여러 외국계 기업에 이력서를 뿌렸다. 하도 많이 제출해서 잊어버릴까봐 Notion으로 리스트를 작성했다. 종종 면접 예상 질문 및 답변들을 추가하고 수정하며 결과를 기다렸다.</p><img src="/2022/04/23/Retrospect/Junior/2.png" class="" title="외국계 기업 지원 리스트"><p>그리고 당연하겠지만 돌아오는 메일이 없었다. 간혹 한 장씩 날라오면 전부 <b>Unfortunately…</b>로 메일이 시작됐다.<br>이 때 쯤에는 외국계 기업이라는 목표를 거의 포기했었다. 애초에 외국계 기업 TO가 적으니 당연한거지..라며 납득하고 있던 찰나, 운 좋게 미국 스타트업의 한국지부에서 인턴을 뽑는다는 소식을 들었다.</p><p>이게 마지막이다 하면서 포트폴리오와 이력서를 다시 재정비했고, 운 좋게 면접까지 모두 합격하여 인턴으로 선발됐다.<br>아직도 생각하면 운이 정말 좋았던 것 같다. 하루 전에 영어로 2시간 30분 동안 기술 + 인성 면접을 본다고 통보받아 거의 자포자기 했는데, 면접관들께서 너무 좋게 봐주셨다.</p><img src="/2022/04/23/Retrospect/Junior/6.png" class="" title="외국계 스타트업 인턴 합격"><h4 id="국내-기업-정규직-12개-11승-1패-2021년-상반기-2021년-하반기"><a href="#국내-기업-정규직-12개-11승-1패-2021년-상반기-2021년-하반기" class="headerlink" title="국내 기업 정규직 12개: 11승 1패 (2021년 상반기 - 2021년 하반기)"></a>국내 기업 정규직 12개: 11승 1패 (2021년 상반기 - 2021년 하반기)</h4><p>국내 기업에서는 대승을 거뒀다. 해외와 상반되는 결과에 기분이 밍숭맹숭했다.<br>참고로 1패는 <code>네이버</code>인데, 코딩테스트를 합격했지만 고민 끝에 면접을 보지 않아서 불합격으로 분류했다. 면접까지 봤으면 최종 결과가 어떻게 나왔을지 잘 모르겠다.</p><img src="/2022/04/23/Retrospect/Junior/4.png" class="" title="국내 기업 정규직 지원 결과"><p>포트폴리오를 뜯어고치고 github를 즐기차게 꾸며놨더니 모든 회사들이 너무 마음에 든다며 만족해하셨다. 덕분에 코딩테스트를 노답으로 보더라도 포트폴리오를 이렇게까지 잘 만든 내가 궁금하다며 면접까지 강제로 합격되는 경우도 허다했다.</p><p>이렇게 정규직 포지션으로 기업을 합격했지만, 위에 외국계 기업에서 인턴으로 합격했기 때문에 이 모든 것들을 포기하고 외국계 기업 인턴을 선택했다.</p><h4 id="최종-기업-선택-2021년-하반기-인턴-중인-외국계-스타트업-S사로-결정"><a href="#최종-기업-선택-2021년-하반기-인턴-중인-외국계-스타트업-S사로-결정" class="headerlink" title="최종 기업 선택 (2021년 하반기): 인턴 중인 외국계 스타트업 S사로 결정"></a>최종 기업 선택 (2021년 하반기): 인턴 중인 외국계 스타트업 S사로 결정</h4><p>인턴십을 진행했던 S사에서 배울 점이 많았고 모두가 친절했으며 무엇보다 외국계 회사 경험을 실제로 한다는게 내게 너무 꿈만같았다. 또한 다들 한국이 아닌 <strong>세상을 상대로 경쟁하는 사람</strong>인지라 엄청난 괴물급 스펙을 가진 인재들이어서, 여기에 있으면 여러모로 발전할 수 있겠구나 생각했다.</p><p>그래서 11월에 네이버 면접을 고민했지만, 결국 네이버를 포기하고 인턴 중인 S사를 선택했다. 인턴십이 끝나고 12월 말에 CEO와 간단한 온라인 미팅(면접)을 통해 정규직을 확정받았고, 2022년 1월부터 정규직으로 근무하기 시작했다. 그렇게 대학 졸업 1개월 전에 취뽀를 해버렸다.</p><p>아 맨 처음에 오퍼메일을 받았을 때 <strong>1-year appointment period</strong>라고 적혀있어 이건 뭔가 싶었는데, 알고보니 정규직이 맞고 1년마다 연봉 갱신한다는 의미에서 이 단어가 들어갔다고 하더라.</p><img src="/2022/04/23/Retrospect/Junior/5.png" class="" title="정규직 오퍼메일"><h4 id="기타-기업-찾기-고르기"><a href="#기타-기업-찾기-고르기" class="headerlink" title="기타: 기업 찾기 & 고르기"></a>기타: 기업 찾기 & 고르기</h4><ol><li><p>기업 찾기</p><ul><li><a href="https://github.com/jojoldu/junior-recruit-scheduler">jojoldu/junior-recruit-scheduler</a>: 주니어 개발자 채용 정보</li><li><a href="https://github.com/milooy/remote-or-flexible-work-company-in-korea">milooy</a>: 한국 자율/원격 출퇴근 회사 리스트</li><li><a href="https://github.com/gcreddy42/hiring2020">gcreddy42/hiring2020</a>: Internship status of companies - COVID-19</li></ul><p>기본적으로 github에 검색을 해보면 정보가 많이 나온다. 대기업은 누구나 다 알테니 중소기업이나 (특히) 스타트업에 관심있는 사람들은 github를 활용하는 것을 추천한다.</p></li><li><p>기업 고르기 (feat. 좆소 거르기)</p><ul><li><p><strong><code>LinkedIn</code>을 사용하는 직원이 많은 회사로 가자</strong><br>좆소 기업들의 특징이 <strong>개발 직군에 대한 정확한 지식 없어 고나리질</strong> 을 한다는 것인데, 모든 좆소가 그런건 아니겠지만 대부분 국비지원 출신들이 고위직에 있을 경우 이런 사태가 잘 발생한다. 좆소 경험이 있는 지인에게 듣길, 1년 과정 국비지원 출신 상사가 4년제 컴퓨터공학과 출신 지인에게 <b>‘이렇게 일을 못하시다니 국비지원 수업 좀 들어보는거 어때요?’</b>라며 큰소리를 치기도 했단다.</p><p>국비지원이라도 기초부터 잘 공부해서 취직하면 할 말 없겠지만, 1년 정도의 커리큘럼 가지고는 CS공부를 했다고 말하기엔 다소 무리가 있다. 괜히 4년제 대학에 컴퓨터공학과가 있을까.<br>그 사람들은 <b>더닝 크루거 효과의 멍청함의 피크(좆문가)</b>의 단계에 있다. 즉 아무리 열심히 설명해도 자신이 무조건 맞으며 개발자의 말을 못 알아듣는 상황이다.</p><img src="/2022/04/23/Retrospect/Junior/3.png" class="" title="더닝 크루거 효과"><p>말이 길어졌는데 이제 <code>LinkedIn</code>에 대한 이유를 설명해보겠다. 개발자들의 이직 과정은 꽤 재밌다. <strong>직접 다른 회사에 이력서를 제출</strong>하거나 <strong>헤드헌터들에게 이직 제안을 받고 바로 코딩테스트와 면접을 보는 경우</strong>가 허다한데, 대부분 능력있는 경력직군은 후자로 많이 이직을 선택한다.</p><p>이 때 헤드헌터들이 사용하는 플랫폼이 무엇인가 알아야 하는데, 대부분이 <code>LinkedIn</code>을 사용한다. 그래서 능력있는 개발자들은 기본적으로 <code>LinkedIn</code> 계정을 갖고 있고, 그런 사람들이 많은 회사를 들어가면 SW를 제대로 공부한 사람끼리 서로 의사소통이 잘 되기 때문에 좆소와 매우 거리가 멀어진다.</p></li><li><p><strong>생각보다 도움이 안되는 <code>기업 리뷰 사이트</code></strong><br>대부분 회사를 지원할 때 잡플래닛, 사람인 등 기업 리뷰를 보게 된다. 그런데 막상 기업에 지원해보니 이 리뷰들이 솔직히 도움이 안됐다.<br>그 당시 사람들이 여러 이유로 고통을 받았다고 하더라도, 막상 들어가면 상황이 이미 다 정리되어 매우 편하게 회사생활을 할 수 있는 경우가 있었다. (주변 지인들 + 내 경험담)</p><p>어떻게 생각해보면 당연한 얘기다. 굳이 리뷰 사이트에 들어가서 글을 남기는 사람이 있을까? 엄청난 애사심이나 증오심이 있지 않은 이상 대부분 귀찮다며 사이트 자체도 들어가지 않을 것이다. 당장 네카라쿠배에 들어가보면 별점이 <code>3.8</code> 정도 되는, 생각보다 그렇게 높지 않은 평점을 확인할 수 있다.</p><p>인터뷰 팁도 의외로 도움이 되지 않았다. 매년 바뀌는 문제, 바뀌는 면접관으로 적중률이 생각보다 높지 않았다. 굳이 나오면.. 포켓몬빵에서 피카츄 걸리는 확률로 기업 인터뷰 후기에 있는 문제가 나왔던 것 같다.</p></li><li><p><strong>잠재성 있는 산업 분야 선택하기</strong><br>입사를 하면 연봉 협상을 해야하는데 기업 입장에서는 최대한 적게, 신입 입장에서는 최대한 크게 연봉 협상을 진행해야 한다.</p><p>대부분 회사들이 <b>“우리 회사가 많이 어려워서요, 이 정도면 가능할 것 같습니다”</b>라는 얼토당토 말도 안되는 방식으로 연봉 후려치기를 하는 경우가 많은데, 사전에 이런 말이 나오지 않도록 차라리 <code>의료</code>, <code>교육</code> 등 미래잠재성이 큰 분야를 타겟으로 사업을 운영하는 회사를 선택하는 것도 좋은 방법이다.<br>미래 인류를 위한 사업으로 대회 상금이나 과제 따오는게 다른 분야보다 쉬운 편이고, 그만큼 자본금도 다른 분야에 비해 널널하기 때문이다.<br>(애초에 회사 사정이 어려운걸 우리가 왜 이해해야 하는지 잘 모르겠다. 회사가 어렵다? 그건 CEO 잘못이다.)</p><p>참고로 이러한 분야를 선택한다고 해서 연봉이 극적으로 올라가는건 아니다. 연봉협상은 말빨이다. 말빨로 상대방이 정신차리지 못하도록 탈탈탈 호로록 털어버리는 것이다.</p></li></ul></li></ol><p><br><br></p><h2 id="5-📖-서류-인터뷰-준비법"><a href="#5-📖-서류-인터뷰-준비법" class="headerlink" title="5. 📖 서류 & 인터뷰 준비법"></a>5. 📖 서류 & 인터뷰 준비법</h2><p>서류 및 인터뷰는 외국계를 준비했을 때 기준으로 적어보겠다. 왜냐면 개인적으로 한국의 1년 후 = 미국의 현재 실리콘밸리 환경이라고 생각하기 때문이다.<br>(나만 느끼는건지 모르겠는데, 미국의 시장상황을 보면 항상 앞으로의 한국 미래인 것 같음…)</p><ul><li>서류: 왠만하면 한 페이지에 전부 내역들을 꽉꽉 채우자. 그 동안 한게 없다면 빈칸을 채우는게 어려울거고, 많은 활동을 해왔다면 한 페이지 안으로 넣는게 은근히 어려울 것이다.<ul><li>포트폴리오: 못해도 당당히 얘기할 수 있는 프로젝트를 3개 정도는 준비하자. 없으면 일단 프로젝트라도 만드는 것을 추천한다. 프로젝트로 사람 뽑는데 그것조차 없으면 안된다 ㅠ_ㅠ</li></ul></li><li>인터뷰: 기업 by 기업이지만, 보통 외국계는 여러 번의 면접이 있다. 지금 이 글을 쓰는 시점에서도 한국도 슬슬 몇 단계의 면접을 진행한다고 하는데…<ul><li>라이브 코딩: 문제 하나 당 2가지의 알고리즘을 준비할 것<ul><li>물론 코딩을 예쁘게 쫙 하면 정말 좋다. 답도 맞추면 금상첨화다. 다만 대부분의 한국인들이 착각하는 것이 있는데, 여기서 보는 것은 지원자의 실력 뿐만 아니라 <code>이 사람이 얼마나 적극적으로 커뮤니케이션을 하는가</code>이다. 즉, 모르겠으면 면접관한테 <em>“같이 의논 가능하실까요? 저는 ~~~까지 생각을 해봤는데, ㅇㅇㅇ님은 어떻게 생각하세요?”</em> 라고 물어보기라도 하자. 실제 외국인 직장 동료들에게 듣기로, 대부분 한국 사람들은 라이브코딩을 하면 “잠시만요” 하면서 문제를 푸느라 묵묵부답을 하는 경우가 많은데, 이게 정말 마이너스 요소라고 한다. 문제를 알든 모르든 상관없으니 일단 <code>말을 하자</code></li><li>라이브 코딩에서 자주 나오는 질문이 있다. 문제를 다 풀었다면, <strong>“이걸 효율적으로 코드 개선을 할 수 있을까요?”</strong> 이다. 이 질문에 대응하기 위해서, 알고리즘을 2개 정도는 생각을 해보도록 하자.</li></ul></li><li>기술 면접: 이건 바로 맞는 답을 해야한다. 단, 여기서 주의할 점은 <code>말을 적극적으로 하기</code>이다. 일단 말을 열심히 해야 답이 틀려도 좋은 인상을 남길 수 있다.</li><li>인성 면접<ul><li>사실 인성면접 같은 경우에는 대부분의 사람들이 성격에 큰 문제가 없다면 합격할 가능성이 높다. 이 단계까지 왔다면, 실력은 인정됐으나 같이 협업하기에 괜찮은 사람인지 사람 대 사람으로 스몰토크 하는거와 비슷하기 때문이다.</li><li>만약에 인성 면접이 두렵다, 하는 사람들은 <strong>심리학 책</strong>을 읽는 것을 추천한다. 물론 책을 읽는다고 심리 전문가가 될 수 있는건 아니지만, 한 번 읽어보면 인간관계에 있어 상황에 따른 판단력을 키울 수 있다. 이게 면접에서도 도움이 되는게, 면접관의 성격을 빠르게 파악할 수 있고 그에 따라 적절히 대응을 할 수 있기 때문이다. 책은 인터넷에 검색해보고 마음에 드는 걸로 읽어보는 것을 추천한다. 내용은 다르지만 모든 책들이 말하는 본질적인 것은 동일하기 때문이다.</li></ul></li></ul></li></ul><p><br><br></p><h2 id="6-📚-최종-이력서-포트폴리오-기타-스펙"><a href="#6-📚-최종-이력서-포트폴리오-기타-스펙" class="headerlink" title="6. 📚 최종 이력서 / 포트폴리오 / 기타 스펙"></a>6. 📚 최종 이력서 / 포트폴리오 / 기타 스펙</h2><ul><li>이력서: 사실 이력서는 만들지 않았다. 간단하게 형식상 내용만 채우고, 위에서 언급했듯이 포트폴리오를 중심으로 서류를 꾸렸다.</li><li>포트폴리오: <a href="https://dev-rubykim.vercel.app/">https://dev-rubykim.vercel.app/</a></li><li>기타 스펙: OPIc IH (딱 하나..)</li></ul><p><br><br></p><h2 id="7-💼-취업-이후로는"><a href="#7-💼-취업-이후로는" class="headerlink" title="7. 💼 취업 이후로는?"></a>7. 💼 취업 이후로는?</h2><p>학교 과제로 뻘뻘대던 시절이 끝나고, 나름의 인간으로서 권리를 누릴 수 있게 되었다. 이젠 하루에 3~4시간을 자게 되었다. 더 자야하는걸 아는데 몸뚱아리가 너무 고생해서 주인 말을 안듣는 반항아가 되었다… ㅠㅠ</p><p>회사 근무를 끝마치면 근무 관련 기술(AWS, React 등)이나 영어공부를, 그리고 부업(블로그, 유튜브 등)을 하고 있다. 또한 직업을 바꾸기 위해 이제는 이것저것 관심있는 분야를 하나 씩 건들면서 내 재능을 확인하는 중이다. <del>항상 얘기하지만 컴퓨터 하기 진짜 싫다 ㅠㅠ</del></p><p>이 글이 취업을 원하는 누군가에게 도움이 되길 바라며, 모두가 원하는 직종으로 빠르게 합격했으면 좋겠다.</p>]]></content>
<categories>
<category> 🎈 Retrospect </category>
</categories>
<tags>
<tag> Retrospect </tag>
<tag> Job </tag>
</tags>
</entry>
<entry>
<title>[React.js] React 라이프 사이클</title>
<link href="/2022/04/22/Frontend/Reactjs/ReactLifeCycle/"/>
<url>/2022/04/22/Frontend/Reactjs/ReactLifeCycle/</url>
<content type="html"><![CDATA[<h2 id="React-Life-Cycle"><a href="#React-Life-Cycle" class="headerlink" title="React Life Cycle"></a>React Life Cycle</h2><hr><p>Reacts는 컴포넌트(component) 기반의 View를 중심으로 한 라이브러리이다.<br>따라서 각각의 컴포넌트에는 라이프사이클, 즉 컴포넌트의 <code>수명 주기</code>가 존재하는데, 컴포넌트의 수명은 보통 <strong>페이지에서 렌더링되기 전인 준비 과정에서 시작하여 페이지에서 사라질 때 끝난다</strong>.</p><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">const</span> <span class="token function-variable function">App</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span> <span class="token operator"><</span>div<span class="token operator">></span> <span class="token operator"><</span>h1<span class="token operator">></span>Hello World<span class="token operator"><</span><span class="token operator">/</span>h1<span class="token operator">></span> <span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token punctuation">;</span>ReactDOM<span class="token punctuation">.</span><span class="token function">render</span><span class="token punctuation">(</span><span class="token operator"><</span>App <span class="token operator">/</span><span class="token operator">></span><span class="token punctuation">,</span> document<span class="token punctuation">.</span><span class="token function">querySelector</span><span class="token punctuation">(</span><span class="token string">"#root"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span></code></pre><p>아래의 사진이 바로 리엑트 라이프 사이클을 나타낸 것이다.<br>(사이트는 <a href="https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/">여기</a> 참고)</p><img src="/2022/04/22/Frontend/Reactjs/ReactLifeCycle/1.png" class="" title="React 라이프사이클 다이어그램"><p><br><br></p><h2 id="Mount-생성될-때"><a href="#Mount-생성될-때" class="headerlink" title="Mount (생성될 때)"></a>Mount (생성될 때)</h2><hr><ol><li><p>constructor</p><ul><li>페이지 로드 되고 컴포넌트가 만들어질 때 처음으로 실행됨</li><li>초기 state 설정이 필요할 때 사용됨</li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// Class</span><span class="token keyword">class</span> <span class="token class-name">Example</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{</span> <span class="token function">constructor</span><span class="token punctuation">(</span><span class="token parameter">props</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">super</span><span class="token punctuation">(</span>props<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">this</span><span class="token punctuation">.</span>state <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token literal-property property">count</span><span class="token operator">:</span> <span class="token number">0</span> <span class="token punctuation">}</span><span class="token punctuation">;</span><span class="token punctuation">}</span><span class="token comment">// Hooks</span><span class="token keyword">const</span> <span class="token function-variable function">Example</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">const</span> <span class="token punctuation">[</span>count<span class="token punctuation">,</span>setCount<span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token function">useState</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre></li><li><p>static getDerivedStateFromProps(nextProps, prevState)</p><ul><li>React 16.3버전 이후에 생긴 메서드</li><li>props로 받아 온 값을 state에 동기화시키는 용도</li><li>컴포넌트가 마운트, 업데이트될 때 호출됨</li><li>리턴타입을 Javascript Object로 설정해야 함</li><li>리턴된 Object는 State에 반영됨</li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// Class</span><span class="token keyword">class</span> <span class="token class-name">Example</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{</span> <span class="token keyword">static</span> <span class="token function">getDerivedStateFromProps</span><span class="token punctuation">(</span><span class="token parameter">nextProps<span class="token punctuation">,</span> prevState</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>nextProps<span class="token punctuation">.</span>value <span class="token operator">!==</span> prevState<span class="token punctuation">.</span>value<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token literal-property property">value</span><span class="token operator">:</span> nextProps<span class="token punctuation">.</span>value<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre></li><li><p>Render()</p><ul><li>React component의 유일한 필수 메서드</li><li>state 변경이 있으면 side effect 발생</li><li>함수형 컴포넌트에서는 render 사용 없이 렌더링 가능</li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// Class</span><span class="token keyword">class</span> <span class="token class-name">Example</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{</span> <span class="token function">render</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token operator"><</span>div<span class="token operator">></span>컴포넌트<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">// Hooks</span><span class="token keyword">const</span> <span class="token function-variable function">example</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token operator"><</span>div<span class="token operator">></span>컴포넌트<span class="token operator"><</span><span class="token operator">/</span>div<span class="token operator">></span><span class="token punctuation">}</span></code></pre></li><li><p>componentDidMount()</p><ul><li>컴포넌트가 DOM에 추가 된 후 실행</li><li>DOM과 상호작용하거나 서드파티 라이브러리들을 사용하는 코드들을 여기서 작성 (ajax 등)</li><li>함수형 Hooks에서는 useEffect를 활용하여 구현<ul><li>useEffect의 [] 의존성 배열을 지워야 똑같은 메소드로 구현할 수 있음</li></ul></li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// Class</span><span class="token keyword">class</span> <span class="token class-name">Example</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{</span> <span class="token function">componentDidMount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">// Hooks</span><span class="token keyword">const</span> <span class="token function-variable function">Example</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre></li></ol><p><br><br></p><h2 id="Update-업데이트-할-때"><a href="#Update-업데이트-할-때" class="headerlink" title="Update (업데이트 할 때)"></a>Update (업데이트 할 때)</h2><hr><ol><li><p>static getDerivedStateFromProps(nextProps, prevState)</p><ul><li>Mount 단계와 동일</li></ul></li><li><p>shouldComponentUpdate</p><ul><li>리턴 타입은 True, False</li><li>리턴되는 결과에 따라 DOM에 리 렌더링을 여부를 결정</li><li>성능 개선을 위해 사용이 가능</li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// Class</span><span class="token keyword">class</span> <span class="token class-name">Example</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{</span> <span class="token function">shouldComponentUpdate</span><span class="token punctuation">(</span><span class="token parameter">nextProps</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">return</span> nextProps<span class="token punctuation">.</span>value <span class="token operator">!==</span> <span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>value <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">// Hooks</span><span class="token keyword">const</span> Example <span class="token operator">=</span> React<span class="token punctuation">.</span><span class="token function">memo</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token parameter">prevProps<span class="token punctuation">,</span> nextProps</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> nextProps<span class="token punctuation">.</span>value <span class="token operator">===</span> prevProps<span class="token punctuation">.</span>value <span class="token punctuation">}</span><span class="token punctuation">)</span></code></pre></li><li><p>Render()</p><ul><li>Mount 단계와 동일</li></ul></li><li><p>getSnapshotBeforeUpdate</p><ul><li>Virtual DOM이 실제 DOM에 반영되기 직전에 실행됨</li><li>이전과 현재의 props와 state애 접근 가능</li><li>return으로 넘겨진 값은 componentDidUpdate의 3번째 인자로 전달됨</li><li>채팅 화면처럼 스크롤 위치를 따로 처리하는 작업이 필요한 UI에서 주로 사용</li><li>함수형에서는 아직 이 기능을 대처할만한 hook이 없음</li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token keyword">class</span> <span class="token class-name">Example</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{</span> <span class="token function">getSnapshotBeforeUpdate</span><span class="token punctuation">(</span><span class="token parameter">prevProps<span class="token punctuation">,</span> prevState</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>prevProps<span class="token punctuation">.</span>list<span class="token punctuation">.</span>length <span class="token operator"><</span> <span class="token keyword">this</span><span class="token punctuation">.</span>props<span class="token punctuation">.</span>list<span class="token punctuation">.</span>length<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword">const</span> list <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>listRef<span class="token punctuation">.</span>current <span class="token keyword">return</span> list<span class="token punctuation">.</span>scrollHeight <span class="token operator">-</span> list<span class="token punctuation">.</span>scrollTop <span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token keyword">null</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre></li><li><p>componentDidUpdate</p><ul><li>매 업데이트마다 UI sync와 서드파티 라이브러리를 사용하는 코드 작성</li><li>리랜더링을 완료 후 실행: 업데이트가 끝난 직후이므로 DOM관련 처리를 해도 무방</li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// Class</span><span class="token keyword">class</span> <span class="token class-name">Example</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{</span> <span class="token function">componentDidUpdate</span><span class="token punctuation">(</span><span class="token parameter">prevProps<span class="token punctuation">,</span> prevState</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token comment">// Hooks</span><span class="token keyword">const</span> <span class="token function-variable function">Example</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre></li></ol><p><br><br></p><h2 id="UnMount-제거할-때"><a href="#UnMount-제거할-때" class="headerlink" title="UnMount (제거할 때)"></a>UnMount (제거할 때)</h2><hr><ol><li><p>ComponentWillUnMount</p><ul><li>DOM에서 컴포넌트가 지워질때 실행</li><li>컴포넌트와 관련된 것을 정리하는데 사용<br>ex) 로그아웃시 주 구성 Component를 해제하기 전에 사용자 세부정보와 모든 인증 토큰을 지운다거나 setInterval을 clear하는 등에 사용</li><li>함수영 컴포넌트에서는 useEffect CleanUp 함수로 구현</li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// Class</span><span class="token keyword">class</span> <span class="token class-name">Example</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{</span> <span class="token function">coomponentWillUnmount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span><span class="token punctuation">}</span><span class="token comment">// Hooks</span><span class="token keyword">const</span> <span class="token function-variable function">Example</span> <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token function">useEffect</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token keyword">return</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span> <span class="token operator">...</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token punctuation">}</span></code></pre></li><li><p>componentDidCatch</p><ul><li>컴포넌트 렌더링 도중 에러가 발생했을 때 어플리케이션을 멈추지 않고 오류 UI를 보여줌</li><li>곧 Hooks에 해당 라이프 사이클 메서드 추가 예정</li></ul><pre class="language-javascript" data-language="javascript"><code class="language-javascript"><span class="token comment">// Class</span><span class="token keyword">class</span> <span class="token class-name">Example</span> <span class="token keyword">extends</span> <span class="token class-name">React<span class="token punctuation">.</span>Component</span> <span class="token punctuation">{</span> <span class="token function">componentDidCatch</span><span class="token punctuation">(</span><span class="token parameter">error<span class="token punctuation">,</span> info</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Error'</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span></code></pre></li></ol>]]></content>
<categories>
<category> ✨ Frontend </category>
</categories>
<tags>
<tag> Javascript </tag>
<tag> Frontend </tag>
<tag> React </tag>
</tags>
</entry>
<entry>
<title>Github Wiki에서 TOC 만들기 </title>
<link href="/2022/04/21/Git-Github/Github-Wiki-TOC/"/>
<url>/2022/04/21/Git-Github/Github-Wiki-TOC/</url>
<content type="html"><![CDATA[<img src="/2022/04/21/Git-Github/Github-Wiki-TOC/2.png" class="" title="Github Wiki TOC 예시"><p>종종 프로젝트를 하다보면 wiki의 크기가 커지는 경우가 많은데, 문서 가시성을 위해 wiki에서 TOC(Table Of Content, 목차)를 만드는 방법을 소개해보고자 한다.</p><h2 id="repository-wiki에-접속-후-sidebar-추가하기"><a href="#repository-wiki에-접속-후-sidebar-추가하기" class="headerlink" title="repository wiki에 접속 후 sidebar 추가하기"></a>repository wiki에 접속 후 sidebar 추가하기</h2><hr><img src="/2022/04/21/Git-Github/Github-Wiki-TOC/1.png" class="" title="Github Wiki sidebar 추가"><p><br><br></p><h2 id="아래의-형태로-원하는-항목-작성"><a href="#아래의-형태로-원하는-항목-작성" class="headerlink" title="아래의 형태로 원하는 항목 작성"></a>아래의 형태로 원하는 항목 작성</h2><hr><pre class="language-markdown" data-language="markdown"><code class="language-markdown"><span class="token title important"><span class="token punctuation">#</span> My menu</span><span class="token list punctuation">*</span> <span class="token url">[<span class="token content">목차1</span>][<span class="token variable">home</span>]</span><span class="token list punctuation">*</span> <span class="token url">[<span class="token content">목차2</span>][<span class="token variable">techdocs</span>]</span><span class="token list punctuation">*</span> <span class="token url">[<span class="token content">목차3</span>][<span class="token variable">usermanual</span>]</span><span class="token url-reference url"><span class="token punctuation">[</span><span class="token variable">home</span><span class="token punctuation">]</span><span class="token punctuation">:</span> https://github.com/myproject/wiki/목차1</span><span class="token url-reference url"><span class="token punctuation">[</span><span class="token variable">techdocs</span><span class="token punctuation">]</span><span class="token punctuation">:</span> https://github.com/myproject/wiki/목차2</span><span class="token url-reference url"><span class="token punctuation">[</span><span class="token variable">usermanual</span><span class="token punctuation">]</span><span class="token punctuation">:</span> https://github.com/myproject/wiki/목차3</span></code></pre><ul><li>위의 코드가 이해가 안된다면 기존의 마크다운처럼 작성 후 변경 에디터로 코드를 변경하자: <a href="https://ecotrust-canada.github.io/markdown-toc/">https://ecotrust-canada.github.io/markdown-toc/</a><ul><li>변경한 코드에서 <code><small> ... </small></code> 부분은 지워도 괜찮다.</li></ul></li></ul>]]></content>
<categories>
<category> 💾 Etc </category>
</categories>
<tags>
<tag> Github </tag>
<tag> Markdown </tag>
</tags>
</entry>
<entry>
<title>[Hexo] Github Blog 백업하기</title>
<link href="/2022/04/15/Hexo/Backup/"/>
<url>/2022/04/15/Hexo/Backup/</url>
<content type="html"><![CDATA[<p>기본적인 블로그 세팅이 끝났다.<br>이전 포스트를 따라 블로그 세팅을 했다면, 실질적으로 .md파일이 저장되는 repository가 없음을 확인할 수 있다.<br>즉 다른 컴퓨터 환경에서 블로그 포스트를 이어서 작성할 수 없으며, .md파일들을 백업하지 않는 이상 해당 데이터들이 손실됐을 때 저 스틱스 강에 영원한 쎄이굿바이를 외쳐야 한다.<br>테마도 마찬가지다. 오픈소스 특징으로 테마도 항상 업데이트되는데, 모두가 사람인지라 코드가 항상 완벽할 수 없다. 그래서 최신의 테마를 가져와서 프로그램을 구동하다보면 치명적인 에러가 발생하는 경우가 많다.</p><p>이러한 불상사를 막기 위해 .md파일과 테마를 백업할 수 있도록 세팅을 진행해보자.</p><h2 id="사전-준비"><a href="#사전-준비" class="headerlink" title="사전 준비"></a>사전 준비</h2><hr><ul><li><a href="/2022/04/07/Hexo/Install/" title="[Hexo] Markdown으로 Github Blog를 만들어보자">[Hexo] Markdown으로 Github Blog를 만들어보자</a></li><li><a href="/2022/04/12/Hexo/InitTheme/" title="[Hexo] Github Blog 테마를 자유롭게 선택 및 수정해보자">[Hexo] Github Blog 테마를 자유롭게 선택 및 수정해보자</a></li></ul><p><br><br></p><h2 id="백업-Repository-생성하기"><a href="#백업-Repository-생성하기" class="headerlink" title="백업 Repository 생성하기"></a>백업 Repository 생성하기</h2><hr><p>각자의 github에 접속하여 2개의 repository를 생성한다.</p><ul><li>theme를 저장할 repository</li><li>.md파일을 저장할 repository</li></ul><p><br><br></p><h2 id="theme-백업하기"><a href="#theme-백업하기" class="headerlink" title="theme 백업하기"></a>theme 백업하기</h2><hr><p><code>themes/테마명</code> 내에서 다음의 명령어들을 실행한다.</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 원격 저장소 변경(theme url로 된 세팅을 자신의 repository url로 재세팅)</span><span class="token function">git</span> remote set-url origin <span class="token string">"theme를 저장할 repository 주소"</span><span class="token comment"># 테마 내용 백업</span><span class="token function">git</span> commit <span class="token parameter variable">-m</span> <span class="token string">"theme backup"</span><span class="token function">git</span> push origin</code></pre><p><br><br></p><h2 id="md-파일-백업하기"><a href="#md-파일-백업하기" class="headerlink" title=".md 파일 백업하기"></a>.md 파일 백업하기</h2><hr><p>hexo blog 디렉토리에서 .md파일을 저장할 repository를 세팅해준다.</p><pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># git 초기화</span><span class="token function">git</span> init<span class="token comment"># 원격 저장소 등록</span><span class="token function">git</span> remote <span class="token function">add</span> origin <span class="token string">".md파일을 저장할 repository 주소"</span><span class="token comment"># 현재 내용 백업</span><span class="token function">git</span> <span class="token function">add</span> <span class="token builtin class-name">.</span><span class="token function">git</span> commit <span class="token parameter variable">-m</span> <span class="token string">"blog backup"</span><span class="token function">git</span> push origin</code></pre><p><br><br></p><h2 id="선택-theme폴더-submodule-추가"><a href="#선택-theme폴더-submodule-추가" class="headerlink" title="(선택) theme폴더 submodule 추가"></a>(선택) theme폴더 submodule 추가</h2><hr><ul><li>이제부턴 다른 환경에서 이 백업파일들을 클론하면 .md파일들과 테마들이 그대로 유지된다.<br>다만 git clone을 두 번 써야 한다는 불편함이 있는데, 한 번의 git clone으로 theme도 자동으로 클론할 수 있도록 세팅을 해준다.<br>이 작업은 hexo blog 디렉토리에서 진행한다. 아래의 명령어를 잘 입력하면 자동으로 theme도 같이 clone 때 다운받아진다.<pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token comment"># 기존의 <themes/테마명>를 삭제</span><span class="token function">rm</span> <span class="token parameter variable">-rf</span> themes/테마명<span class="token comment"># 백업해둔 theme repository를 submodule로 추가</span><span class="token function">git</span> submodule <span class="token function">add</span> <span class="token string">"theme를 저장한 repository 주소"</span><span class="token comment"># 현재 내용 백업</span><span class="token function">git</span> <span class="token function">add</span> <span class="token builtin class-name">.</span><span class="token function">git</span> commit <span class="token parameter variable">-m</span> <span class="token string">"blog theme submodule"</span><span class="token function">git</span> push origin</code></pre></li><li>앞으로 새로운 환경에서 블로그를 다시 운영할 때 아래의 명령어로 기존 환경을 재구성해준다.<pre class="language-bash" data-language="bash"><code class="language-bash"><span class="token function">git</span> clone <span class="token parameter variable">--recursive</span> <span class="token string">".md파일을 저장한 repository 주소"</span> blog<span class="token builtin class-name">cd</span> blog<span class="token function">npm</span> <span class="token function">install</span></code></pre></li></ul>]]></content>
<categories>
<category> 🏹 Blog </category>
</categories>