Openstack 에서 운영중인 VM 용량 늘리기

리눅스/OpenStack|2023. 10. 19. 11:55
반응형

Flavor 를 변경하는 방법과 disk 파일의 크기를 직접 늘려주는 방법이 있는데, 여기에서는 disk 파일 크기를 바로 변경하는 더 쉬운 방법을 안내 드리겠습니다.

 

변경하고자 하는 master 라는 이름의 VM 이 어느 컴퓨트 노드에 있는지 확인합니다.

(Controller 서버에서)

# openstack server show master |grep hostname
| OS-EXT-SRV-ATTR:hypervisor_hostname | compute1                                                 |

 

(해당 컴퓨트 노드에서)

사용중인 VM 의 PID 값 확인 후 종료합니다.

# ps -ef|grep disk
root        1110       1  0 02:37 ?        00:00:00 /usr/libexec/udisks2/udisksd
libvirt+    2788       1 99 02:38 ?        00:00:08 /usr/bin/qemu-system-x86_64 -name guest=instance-00000006,debug-threads=on -S -object {"qom-type":"secret","id":"masterKey0","format":"raw","file":"/var/lib/libvirt/qemu/domain-1-instance-00000006/master-key.aes"} -machine pc-i440fx-6.2,usb=off,dump-guest-core=off,memory-backend=pc.ram -accel kvm -cpu Skylake-Client-IBRS,ss=on,vmx=on,pdcm=on,hypervisor=on,tsc-adjust=on,clflushopt=on,umip=on,md-clear=on,stibp=on,arch-capabilities=on,ssbd=on,xsaves=on,pdpe1gb=on,ibpb=on,ibrs=on,amd-stibp=on,amd-ssbd=on,rsba=on,skip-l1dfl-vmentry=on,pschange-mc-no=on,hle=off,rtm=off -m 8192 -object {"qom-type":"memory-backend-ram","id":"pc.ram","size":8589934592} -overcommit mem-lock=off -smp 4,sockets=4,dies=1,cores=1,threads=1 -uuid f6aa6879-0ea4-4be8-a610-d1abcd60c9ab -smbios type=1,manufacturer=OpenStack Foundation,product=OpenStack Nova,version=25.2.0,serial=f6aa6879-0ea4-4be8-a610-d1abcd60c9ab,uuid=f6aa6879-0ea4-4be8-a610-d1abcd60c9ab,family=Virtual Machine -no-user-config -nodefaults -chardev socket,id=charmonitor,fd=31,server=on,wait=off -mon chardev=charmonitor,id=monitor,mode=control -rtc base=utc,driftfix=slew -global kvm-pit.lost_tick_policy=delay -no-hpet -no-shutdown -boot strict=on -device piix3-usb-uhci,id=usb,bus=pci.0,addr=0x1.0x2 -blockdev {"driver":"file","filename":"/var/lib/nova/instances/_base/bf15376deac35c8c707e130fb5d70882999b77d2","node-name":"libvirt-2-storage","cache":{"direct":true,"no-flush":false},"auto-read-only":true,"discard":"unmap"} -blockdev {"node-name":"libvirt-2-format","read-only":true,"cache":{"direct":true,"no-flush":false},"driver":"raw","file":"libvirt-2-storage"} -blockdev {"driver":"file","filename":"/var/lib/nova/instances/f6aa6879-0ea4-4be8-a610-d1abcd60c9ab/disk","node-name":"libvirt-1-storage","cache":{"direct":true,"no-flush":false},"auto-read-only":true,"discard":"unmap"} -blockdev {"node-name":"libvirt-1-format","read-only":false,"cache":{"direct":true,"no-flush":false},"driver":"qcow2","file":"libvirt-1-storage","backing":"libvirt-2-format"} -device virtio-blk-pci,bus=pci.0,addr=0x4,drive=libvirt-1-format,id=virtio-disk0,bootindex=1,write-cache=on -netdev tap,fd=34,id=hostnet0,vhost=on,vhostfd=36 -device virtio-net-pci,host_mtu=1450,netdev=hostnet0,id=net0,mac=fa:16:3e:cb:7e:47,bus=pci.0,addr=0x3 -add-fd set=3,fd=33 -chardev pty,id=charserial0,logfile=/dev/fdset/3,logappend=on -device isa-serial,chardev=charserial0,id=serial0 -device usb-tablet,id=input0,bus=usb.0,port=1 -device usb-kbd,id=input1,bus=usb.0,port=2 -audiodev {"id":"audio1","driver":"none"} -vnc 127.0.0.1:0,audiodev=audio1 -device virtio-vga,id=video0,max_outputs=1,bus=pci.0,addr=0x2 -device virtio-balloon-pci,id=balloon0,bus=pci.0,addr=0x5 -object {"qom-type":"rng-random","id":"objrng0","filename":"/dev/urandom"} -device virtio-rng-pci,rng=objrng0,id=rng0,bus=pci.0,addr=0x6 -device vmcoreinfo -sandbox on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny -msg timestamp=on
root        2836    2649  0 02:38 pts/1    00:00:00 grep --color=auto disk

 

# kill -9 2788

 

인스턴스 디렉토리로 들어가 disk 파일의 사이즈를 20G 더 늘려줍니다.

# cd /var/lib/nova/instances/f6aa6879-0ea4-4be8-a610-d1abcd60c9ab

# qemu-img resize disk +20G

Image resized.

 

(Controller 서버에서)

중지되었던 VM 을 다시 가동합니다.

# openstack server start master

 

(VM 에서)

용량 확인 명령으로 초기 20GB 에서 20GB 더 늘린 40GB 사용이 확인되었습니다.

root@master:~# df -h
Filesystem      Size  Used Avail Use% Mounted on
tmpfs           794M  1.7M  793M   1% /run
/dev/vda1        39G   19G   21G  48% /
tmpfs           3.9G     0  3.9G   0% /dev/shm
tmpfs           5.0M     0  5.0M   0% /run/lock
/dev/vda15      105M  6.1M   99M   6% /boot/efi
tmpfs           794M  4.0K  794M   1% /run/user/1000

 

반응형

댓글()

리눅스에서 현재 세션의 명령 히스토리만 삭제하기

리눅스/OS 일반|2023. 10. 17. 08:32
반응형

기존 history 는 남기고 현재 세션의 명령 history 만 삭제하는 방법은 아래와 같습니다.

 

- 목적 : 특별한 작업 로그를 남기지 않을 경우 사용

- 명령어 : # unset HISTFILE

 

반응형

댓글()

Ubuntu 22.04 에서 Ansible 2.10.8 설치 및 설정, 플레이북 활용

리눅스/OS 일반|2023. 10. 12. 11:34
반응형

Ansible 은 인프라스트럭처 관리와 소프트웨어 프로비저닝을 자동화하기 위한 오픈 소스 도구 및 프레임워크입니다. Ansible 은 다음 3가지의 핵심 구성 요소를 가지고 있습니다.
- 인벤토리 : 관리 대상 호스트 (서버, 가상 머신 등) 의 목록 및 그룹을 정의하는 INI 또는 YAML 파일
- 플레이북 : 작업 (task), 역할 (role), 변수, 조건문 등을 포함한 YAML 파일로, 여러 대상 호스트에서 작업을 수행
- 모듈 : 특정 작업을 수행하기 위한 실행 가능한 코드 블록

 

Ubuntu 22.04 기반에서 Ansible 을 설치, 설정하고 실제로 실행하는 방법을 알아보겠습니다.

 

[테스트를 위한 사전 준비]

- Ubuntu 22.04 기반 서버 3대 (Ansible 서버 1대, 대상 호스트 2대)

 

 

1. 설치

 

Ansible 설치는 굉장히 간단합니다.

Ansible 명령을 수행할 Ansible 서버에만 몇 개의 패키지를 설치하면 되며, 작업을 수행할 서버에 설치할 패키지 또는 Agent 는 없습니다.

(그렇기 때문에 본 매뉴얼의 모든 명령은 Ansible 서버에서만 실행합니다)

Ansible 는 SSH 기반으로 명령을 수행하기 때문에 sshpass 패키지까지 설치해줘야 합니다.

그리고 Ansible 은 Python 으로 제작되었기 때문에 Ansible 설치시 Python 도 같이 설치가 됩니다.

# apt -y update

# apt -y upgrade

# apt -y install ansible sshpass

# ansible --version
ansible 2.10.8
  config file = None
  configured module search path = ['/root/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  executable location = /usr/bin/ansible
  python version = 3.10.12 (main, Jun 11 2023, 05:26:28) [GCC 11.4.0]

 

 

2. 인벤토리 설정

 

1) 인벤토리 파일 생성

관리하는 서버의 정보를 담은 파일을 아래와 같이 생성합니다.

섹션 이름은 서버를 그룹핑하기 위한 명칭으로 적절히 설정하면 되고,

대상 호스트는 IP 또는 도메인으로 입력할 수 있습니다.

섹션 내에 여러대의 호스트 추가가 가능합니다.

# vi servers.ini

[web]
10.101.0.23
[db]
10.101.0.34

 

2) SSH 공개키 복사

Ansible 은 ssh 를 이용하여 대상 호스트로 명령을 수행합니다.

ssh 공개키를 생성하고 대상 호스트에 설정하여두면 Ansible 명령 실행시마다 패스워드를 입력하는 번거로움을 줄일 수 있습니다.

# ssh-keygen 
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): (그냥 엔터)
Enter passphrase (empty for no passphrase): (그냥 엔터)
Enter same passphrase again: (그냥 엔터)
Your identification has been saved in /root/.ssh/id_rsa
Your public key has been saved in /root/.ssh/id_rsa.pub
The key fingerprint is:
SHA256:2bKuWWJfCBqiNnkCYgKZRmI6GEZDynqWbGM41/TsbAk root@kuru80-223962
The key's randomart image is:
+---[RSA 3072]----+
|=B               |
|X+.              |
|Oo  .            |
|++ + o   o       |
|B.@ E + S .      |
|=O.o * o +       |
|.= .. B + .      |
|. +  o * .       |
|      o.o        |
+----[SHA256]-----+

생성된 공개키를 대상 호스트로 복사합니다. 처음 호스트 접속시 패스워드가 필요하지만 키 복사가 완료된 후에는 패스워드가 필요 없게 됩니다.

# ssh-copy-id root@10.101.0.23

# ssh-copy-id root@10.101.0.34

 

3) 연결 테스트

Ansible 에서 주로 사용하는 옵션은 세가지가 있습니다. (help 에서는 더 많은 옵션이 출력됩니다)

-m : 모듈

-i : 인벤토리

-u : 유저명

유저명은 제외하고 아래와 같이 인벤토리 (servers.ini) 에 등록된 모든 호스트에 ping 테스트를 해봅니다.

참고로 all 말고 섹션명을 지정해주면 인벤토리 내의 특정 세션에 등록된 호스트로만 명령을 실행합니다.

# ansible -i servers.ini all -m ping
10.101.0.34 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}
10.101.0.23 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python3"
    },
    "changed": false,
    "ping": "pong"
}

 

 

3. 옵션

 

Ansible 은 기본적으로 작업을 병렬 처리 합니다.

기본 동시 처리되는 호스트 개수는 5개 입니다.

# ansible-config dump |grep -i forks
DEFAULT_FORKS(default) = 5

 

서버의 자원이 충분하여 동시에 처리되는 양을 늘리고자 할 경우 아래와 같이 설정파일을 수정하여 동시처리 개수를 늘릴 수 있습니다.

설정파일은 아래 여러 가지 방법중 한가지 방법을 이용하여 설정할 수 있으며, 우선 순위대로 검색되는 구성 파일으로 적용되어집니다.

- ANSIBLE_CONFIG (환경변수)
- ansible.cfg (현재 디렉토리)
- ~/.ansible.cfg (홈디렉토리)
- /etc/ansible/ansible.cfg

 

디렉토리가 바뀌어도 항상 적용이 가능하도록 세번째 방법으로 설정해보겠습니다.

# vi ~/.ansible.cfg

[defaults]
forks = 10

 

저장만 해도 변경된 것이 확인되었습니다.

# ansible-config dump |grep -i forks
DEFAULT_FORKS(/root/.ansible.cfg) = 10

 

아래는 중요하거나 자주 사용하는 옵션입니다. 모두 [default] 섹션에 넣어주면 됩니다.

- remote_user

: 원격 호스트에 연결할 때 사용할 SSH 사용자 이름을 지정합니다. 기본값은 현재 사용자의 이름입니다. 이 옵션을 설정하여 명시적으로 원격 사용자를 지정할 수 있습니다.
예) remote_user = myuser

 

- private_key_file

: SSH 키 파일의 경로를 지정합니다. 이 옵션을 사용하여 사용자 지정 SSH 키 파일을 사용할 수 있습니다.
예) private_key_file = /path/to/ssh/keyfile

 

- inventory

: 인벤토리 파일의 경로를 지정합니다. 기본적으로 ansible.cfg 파일이 있는 디렉토리에서 inventory 파일을 검색하며, 이 옵션을 사용하여 사용자 정의 인벤토리 파일을 지정할 수 있습니다. 인벤토리 파일의 경로를 지정하면 ansible 명령 실행시 -i 옵션을 이용해 인벤토리 파일을 일일이 명시하지 않아도 됩니다.
예) inventory = /root/servers.ini

 

- roles_path

: 역할 (roles) 디렉토리의 기본 경로를 지정합니다. 이 옵션을 사용하여 역할을 저장하는 디렉토리를 사용자 정의할 수 있습니다.
예) roles_path = /path/to/custom/roles

 

- forks

: 병렬로 실행될 작업 수를 지정합니다. 기본값은 5이며, 시스템 리소스에 따라 적절한 값을 설정할 수 있습니다.
예) forks = 10

 

- become

: 작업을 슈퍼 유저(루트) 권한으로 실행할지 여부를 지정합니다. yes로 설정하면 슈퍼 유저로 작업을 실행합니다.
예) become = yes

 

- become_user

: 슈퍼 유저(루트) 권한으로 작업을 실행할 때 사용할 사용자를 지정합니다.
예) become_user = root

 

- timeout

: SSH 연결 또는 명령 실행의 타임아웃을 지정합니다. 기본값은 10초입니다.
예) timeout = 30

 

 

4. 플레이북 설정

 

플레이북 (playbook) 을 활용한 다양한 예시를 준비했습니다.

 

1) 대상 서버로 파일 복사하기

아래와 같이 플레이북 파일을 작성합니다.

# vi copy.yaml

---
- name: Copy a file to a remote server
  hosts: web
  tasks:
    - name: Copy a file
      copy:
        src: /root/servers.ini
        dest: /root/

 

- 플레이북 파일의 시작은 --- 로 시작하고, 여러개의 작업이 있을 경우 작업 단위마다 - 으로 구분해줘야 합니다.

- hosts : 섹션을 지정합니다. hosts 를 web 섹션으로 하지 않고 all 로 입력 할 경우 인벤토리에 등록된 모든 호스트로 파일을 복사하게 됩니다.

- name : 작업을 구분하기 위한 명칭입니다. (위, 아래 둘다)

- copy : 복사하려는 로컬 파일과 붙여넣으려는 대상 호스트의 디렉토리를 지정합니다.

 

작성한 플레이북을 실행합니다.

# ansible-playbook -i servers.ini copy.yaml

 

2) 패스워드 변경하기

대상 호스트의 root 패스워드를 변경합니다.

# vi chpasswd.yaml

---
- name: Update Remote Server Password
  hosts: all
  tasks:
    - name: Update password
      user:
        name: root
        update_password: always
        password: "{{ '12345678' | password_hash('sha512') }}"

 

- name: 플레이북의 이름을 정의합니다. 이 이름은 플레이북을 식별하기 위해 사용됩니다.
- hosts: 플레이북이 실행될 호스트 그룹을 지정합니다. "all"은 모든 호스트를 대상으로 하는 것을 의미합니다.
- tasks: 플레이북에서 실행할 작업 목록을 정의합니다.
- name: 각 작업의 이름을 지정합니다. 이것은 작업을 식별하기 위한 레이블입니다.
- user 모듈: 이 모듈은 사용자 관리 작업을 수행합니다.
- name: root: user 모듈에 전달된 사용자 이름으로 "root" 사용자를 지정합니다. 이 플레이북은 "root" 사용자의 비밀번호를 변경합니다.
- update_password: always: 사용자 모듈의 update_password 옵션을 "always"로 설정하면 항상 비밀번호를 업데이트하도록 강제합니다.
- password: user 모듈에서 변경할 비밀번호를 정의합니다. 이 플레이북에서는 "12345678"을 password_hash 필터를 사용하여 SHA-512로 해싱한 값을 비밀번호로 설정합니다. 해싱된 비밀번호를 사용하면 보안성을 향상시킬 수 있습니다.

 

작성한 플레이북을 실행합니다.

# ansible-playbook -i servers.ini chpasswd.yaml

 

3) 패키지 설치하기

이 예시는 원격 서버의 APT 패키지 관리자를 사용하여 패키지를 설치합니다.
# vi apt.yaml

---
- name: Install a package on a remote server
  hosts: web
  tasks:
    - name: Install package
      apt:
        name: apache2
        state: present

 

- name: 플레이북의 이름을 정의합니다. 이 이름은 플레이북을 식별하기 위해 사용됩니다.
- hosts: 플레이북이 실행될 호스트 그룹을 지정합니다. "web"은 모든 호스트를 대상으로 하는 것을 의미합니다.
- tasks: 플레이북에서 실행할 작업 목록을 정의합니다.
- apt 모듈: 패키지 설치 작업을 수행합니다.

 

작성한 플레이북을 실행합니다.

# ansible-playbook -i servers.ini apt.yaml

 

4) 데몬 컨트롤 하기

이 예제에서는  Ubuntu 에서 Apache 웹 서버를 시작하는 플레이북을 사용합니다.
# vi apache2.yaml

---
- name: Start Apache Web Server
  hosts: web
  become: yes
  tasks:
    - name: Ensure Apache service is running
      service:
        name: apache2
        state: started


- name: 플레이북의 이름을 지정합니다.
- hosts: 플레이북을 실행할 호스트 그룹 또는 호스트 이름을 지정합니다.
- become: yes: become 키워드를 사용하여 플레이북을 실행할 때 슈퍼유저(루트) 권한으로 실행합니다. 이는 데몬 또는 서비스를 시작하거나 중지할 때 필요한 권한을 얻기 위해 사용됩니다.
- tasks: 수행할 작업 목록을 나열합니다.
- name: 작업의 이름을 지정합니다.
- service 모듈: 서비스 관리 작업을 수행하는 모듈입니다.
- name: apache2: 서비스의 이름을 지정합니다. Ubuntu 에서 Apache 웹 서버는 apache2 로 알려져 있습니다.
- state: started: 서비스를 시작하도록 지정합니다. 이 작업은 Apache 웹 서버가 이미 실행 중인 경우에는 아무 작업도 수행하지 않습니다.

 

작성한 플레이북을 실행합니다.

# ansible-playbook -i servers.ini apache2.yaml

 

5) 사용자 생성 및 그룹 할당
이 예시는 원격 서버에 사용자를 생성하고 그룹에 할당하는 플레이북입니다. user 및 group 모듈을 사용합니다.

# vi useradd.yaml

---
- name: Create a user and assign to a group
  hosts: web
  tasks:
    - name: Create a group
      group:
        name: developers
        state: present

    - name: Create a user
      user:
        name: sysdocu
        groups: developers
        state: present

 

* 설명

- name: 플레이북의 이름을 지정합니다.
- hosts: 플레이북을 실행할 호스트 그룹 또는 호스트 이름을 지정합니다.
- tasks: 수행할 작업 목록을 나열합니다.
- group 및 user 모듈: 그룹 및 사용자 생성 및 할당 작업을 수행합니다.

 

작성한 플레이북을 실행합니다.

# ansible-playbook -i servers.ini useradd.yaml

 

6) 보안 패치 적용
서버에 보안 패치를 적용합니다.
# vi update.yaml

---
- name: Apply security patches
  hosts: all
  tasks:
    - name: Update package cache
      apt:
        update_cache: yes
      become: yes

    - name: Upgrade all packages
      apt:
        upgrade: safe
      become: yes

 

작성한 플레이북을 실행합니다.

# ansible-playbook -i servers.ini update.yaml

 

7) MySQL 설치 및 설정
MySQL 데이터베이스를 설치하고 설정합니다.

DB 생성, 계정 생성 및 DB 권한 부여까지 진행합니다.
# vi mysql.yaml

---
- name: Install MySQL and Configure Database
  hosts: db
  become: yes
  tasks:
    - name: Install MySQL Server
      apt:
        name: mysql-server
        state: present

    - name: Start MySQL Service
      service:
        name: mysql
        state: started

    - name: Install python3-pymysql
      apt:
        name: python3-pymysql
        state: present

    - name: Change MySQL root password
      mysql_user:
        login_user: root
        login_password: ''
        name: root
        password: 12345678
        host: localhost
        login_unix_socket: /var/run/mysqld/mysqld.sock

    - name: Create a MySQL Database
      mysql_db:
        login_user: root
        login_password: 12345678
        name: sysdocudb
        state: present

    - name: Create a MySQL User
      mysql_user:
        name: sysdocu
        password: 12345678
        priv: sysdocudb.*:ALL

    - name: Flush MySQL Privileges
      mysql_user:
        login_user: root
        login_password: 12345678
        name: sysdocu
        host: localhost
        priv: "*.*:ALL,GRANT"
        append_privs: yes

 

작업을 설명하면, 아래와 같이 순차 처리됩니다.

- MySQL 설치

- MySQL 시작

- python3-pymysql 설치 (Ansible 에서 MySQL 관리하기 위해 필요)

- root 패스워드 변경 (null -> 12345678)

- DB 생성

- DB 계정 생성

- 계정에 DB 권한 부여

* 작업별로 MySQL 쿼리 실행을 위해 root 계정정보를 입력해 주었습니다.

 

작성한 플레이북을 실행합니다.

# ansible-playbook -i servers.ini mysql.yaml

 

8) Docker 컨테이너 배포 및 관리

Docker 컨테이너를 배포하고 관리합니다.

플레이북에서 대상 호스트에 Docker 패키지와 docker-py 설치 작업 후 컨테이너를 구동하는 절차로 작성하면 되지만, 여기에서는 Docker 및 docker-py 가 대상 호스트에 설치되었다고 가정하고 컨테이너 구동 방법만 설명드립니다.

 

* 참고 : Docker 및 docker-py 설치 (Ubuntu 22.04)

(대상 호스트에서)

# apt -y install apt-transport-https ca-certificates curl gnupg lsb-release
# curl -fsSL https://download.docker.com/linux/ubuntu/gpg |gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# echo   "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" |tee /etc/apt/sources.list.d/docker.list > /dev/null
# apt -y update
# apt -y install docker-ce docker-ce-cli containerd.io

# apt -y install python3-pip

# pip3 install docker-py

 

플레이북을 작성합니다.

(Ansible 서버에서)

# vi docker.yaml

---
- name: Deploy Docker containers
  hosts: db
  tasks:
    - name: Pull Docker image
      docker_image:
        name: nginx:latest

    - name: Run a Docker container
      docker_container:
        name: my_nginx
        image: nginx:latest
        ports:
          - "80:80"

 

- name: 플레이북의 이름을 지정합니다. 이 이름은 플레이북을 식별하는 레이블입니다.
- hosts: 플레이북을 실행할 호스트 또는 호스트 그룹을 지정합니다. 이 예시에서는 "db" 호스트 그룹에 대한 작업을 수행합니다.
- tasks: 플레이북에서 실행할 작업 목록을 정의합니다.
- name: 각 작업의 이름을 지정합니다. 이것은 작업을 식별하는 레이블입니다.
- docker_image 모듈: 이 모듈은 Docker 이미지 관리 작업을 수행합니다. name 속성은 다운로드하려는 Docker 이미지의 이름을 지정합니다. 이 예시에서는 "nginx:latest" 이미지를 다운로드합니다.
- docker_container 모듈: 이 모듈은 Docker 컨테이너 관리 작업을 수행합니다. name 속성은 컨테이너의 이름을 지정하고, image 속성은 사용할 Docker 이미지를 지정합니다. ports 속성은 컨테이너와 호스트 간의 포트 매핑을 설정합니다. 이 예시에서는 "my_nginx"라는 이름의 컨테이너를 생성하고 "nginx:latest" 이미지를 사용하며, 호스트의 80번 포트와 컨테이너의 80번 포트를 연결합니다.

작성한 플레이북을 실행합니다.

# ansible-playbook -i servers.ini docker.yaml

 

반응형

댓글()

개인 도커 레지스트리 (Docker Registry) 구축하기

반응형

Docker Registry 는 Docker 이미지를 업로드 하거나, 다운로드하여 컨테이너를 생성하는 등 이미지 저장소의 역할을 담당합니다. Docker Hub 와 같이 알려진 공개 Docker Registry 말고, 개인적으로 사용 가능한 Docker Registry 를 직접 만들어 보겠습니다.

보통은 Private Registry 라고 하며 Kubernetes 내에서 생성하고 사설 네트워크로 연결하도록 구성하지만, 여기에서는 별도의 단독 서버 1대 (공인IP) 로만 구성할 예정입니다. Registry 서버가 Kubernetes Cluster 와 동일한 스위치 내에 위치한다면 방화벽을 설치함으로써 Private Registry 과 같은 형태로 만들 수 있습니다. 이런 형태로 서비스에 적용할 예정이라면 스토리지 여러대로 GlusterFS 나 Ceph 를 구성하고 별도로 마운트하고 도커 서비스를 구동할 서버 1대로 구성하면 됩니다.

 

다시 말씀 드리면, 두가지 방식중 아래 방식으로 진행합니다.

- Kubernetes 설치, 스토리지 준비, PV 및 PVC 생성, Registry Pod 생성

- Docker 설치, Registry Container 생성

 

[환경 및 사전준비]

OS : Ubuntu 22.04

/data 디렉토리 생성 (로컬 호스트의 이미지 저장소)

 

 

1. SSL 인증서 생성

 

Registry 를 사용할때 파일을 업로드 하거나 다운로드 하게되는데, 이때 암호화 전송이 필요합니다.

(암호화 전송 없이 http 프로토콜을 사용하는 옵션도 있긴 합니다)

인증서가 없을 경우, Let's encrypt SSL 에서 무료 인증서를 발급받을 수 있습니다.

운영체제에 따라 인증서 발급 명령이 다르므로 아래 포스팅을 확인하여 자신의 운영체제에 맞는 명령을 참고하시기 바랍니다.

https://sysdocu.tistory.com/search/let's%20encrypt

 

발급 방법은 위 포스팅에 있으므로 여기에서는 생략하고 넘어가겠습니다.

이제 도메인 인증서를 생성하였고, 인증서를 master 서버의 /root/certs 디렉토리에 복사해 두었습니다.

- 도메인 : registry.az1.sysdocu.kr

- 인증서 파일 위치 : /opt/registry/certs/

 

 

2. Docker 설치

 

Registry 서비스는 Docker Registry 컨테이너를 이용할 것이기 때문에 Docker 패키지를 설치해야 합니다.

패키지 목록을 최신화하고 업그레이드 합니다.
# apt -y update

# apt -y upgrade
# apt -y install apt-transport-https ca-certificates curl gnupg lsb-release

Docker 공식 GPG 를 설치합니다.
# curl -fsSL https://download.docker.com/linux/ubuntu/gpg |gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

Docker 공식 저장소를 추가합니다.
# echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" |tee /etc/apt/sources.list.d/docker.list > /dev/null

Docker 를 설치하고 확인합니다.

# apt -y update
# apt -y install docker-ce docker-ce-cli containerd.io
# docker --version

Docker version 24.0.6, build ed223bc

 

 

3. Registry 설치 및 가동

 

Docker Hub 에서 Docker Registry 최신버전 이미지를 다운로드 합니다.
# docker pull registry:latest
latest: Pulling from library/registry
7264a8db6415: Pull complete 
c4d48a809fc2: Pull complete 
88b450dec42e: Pull complete 
121f958bea53: Pull complete 
7417fa3c6d92: Pull complete 
Digest: sha256:d5f2fb0940fe9371b6b026b9b66ad08d8ab7b0d56b6ee8d5c71cb9b45a374307
Status: Downloaded newer image for registry:latest
docker.io/library/registry:latest

 

다운로드 된 이미지를 확인합니다.

# docker images
REPOSITORY   TAG       IMAGE ID       CREATED       SIZE
registry     latest    0030ba3d620c   3 weeks ago   24.1MB

 

Registry 에 접근할 사용자를 생성합니다.

사용자 생성 방식은 htpasswd 를 이용하였습니다.

# apt -y install apache2-utils

# mkdir -p /opt/registry/auth

# htpasswd -c -b -B /opt/registry/auth/htpasswd sysdocu 12345678
Adding password for user sysdocu

 
이제 Registry Docker 이미지, SSL 인증서, 사용자 계정이 준비되었습니다.

컨테이너를 다음과 같은 명령으로 가동합니다.
# docker run --name MyRegistry --restart=always -p 5000:5000 \
    -v /opt/registry/auth:/auth \
    -v /opt/registry/certs:/certs \
    -v /data:/var/lib/registry \
    -e "REGISTRY_AUTH=htpasswd" \
    -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
    -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
    -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/fullchain1.pem \
    -e REGISTRY_HTTP_TLS_KEY=/certs/privkey1.pem \
    -e REGISTRY_COMPATIBILITY_SCHEMA1_ENABLED=true \
    -d registry

* 참고

-v: command not found, -e: command not found 등의 에러 출력시 행 사이에 줄이 떨어져 있는 것이므로 메모장에 기입해 빈 행을 없애거나 역슬래시를 제거하여 한줄 명령으로 사용하면 됩니다.

 

* 설명

--name MyRegistry : 실행되는 컨테이너의 이름을 MyRegistry 로 설정합니다.
--restart=always : 컨테이너가 종료되거나 실패할 경우 자동으로 다시 시작하도록 설정합니다.

-p 5000:5000 : 호스트의 포트 5000 과 컨테이너의 포트 5000 을 연결하여 Registry 에 엑세스할 수 있게 합니다.

-v /opt/registry/auth:/auth : 호스트의 /opt/registry/auth 디렉토리와 컨테이너 내의 /auth 디렉토리를 볼륨 마운트합니다. 이 디렉토리는 사용자 인증 정보를 저장하기 위한 것으로, htpasswd 형식의 사용자 인증 파일이 여기에 저장됩니다.
-v /opt/registry/certs:/certs : 호스트의 /opt/registry/certs 디렉토리와 컨테이너 내의 /certs 디렉토리를 볼륨 마운트합니다. 이 디렉토리에는 TLS (SSL) 인증서 및 키 파일이 저장됩니다.
-v /data:/var/lib/registry : 호스트의 /data 디렉토리와 컨테이너 내의 /var/lib/registry 디렉토리를 볼륨 마운트합니다. 여기에는 레지스트리의 이미지 데이터가 저장됩니다.

-e "REGISTRY_AUTH=htpasswd" : 환경 변수를 설정하여 레지스트리가 htpasswd 형식의 사용자 인증을 사용하도록 합니다.
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" : htpasswd 형식의 사용자 인증을 위한 Realm 을 설정합니다.
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd : 사용자 인증 정보를 저장하는 htpasswd 파일의 경로를 지정합니다.
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/fullchain1.pem : TLS (SSL) 인증서 파일의 경로를 설정합니다.
-e REGISTRY_HTTP_TLS_KEY=/certs/privkey1.pem : TLS (SSL) 인증서의 개인 키 파일의 경로를 설정합니다.
-e REGISTRY_COMPATIBILITY_SCHEMA1_ENABLED=true : Docker Registry v2의 호환성을 유지하고 Docker v1/v1 API를 사용할 수 있도록 활성화합니다.
-d registry : 컨테이너를 백그라운드에서 실행하도록 설정하고, 다운로드 받아놓은 registry 라는 Docker Image 를 사용하여 컨테이너를 시작합니다.

 

구동된 컨테이너를 확인합니다.

# docker ps
CONTAINER ID   IMAGE      COMMAND                  CREATED         STATUS         PORTS                                       NAMES
f246853edd47   registry   "/entrypoint.sh /etc…"   6 seconds ago   Up 5 seconds   0.0.0.0:5000->5000/tcp, :::5000->5000/tcp   MyRegistry

 

포트도 5000 번으로 정상적으로 열린것이 확인되었습니다.

# netstat -nltp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN      23260/systemd-resol 
tcp        0      0 0.0.0.0:5000            0.0.0.0:*               LISTEN      54372/docker-proxy  
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      18912/sshd: /usr/sb 
tcp6       0      0 :::5000                 :::*                    LISTEN      54379/docker-proxy  
tcp6       0      0 :::22                   :::*                    LISTEN      18912/sshd: /usr/sb 

 

만들어진 Registry 컨테이너로 로그인을 해봅니다.

계정은 위에서 htpasswd 로 생성했던 계정입니다.

# docker login -u sysdocu -p 12345678 https://registry.az1.sysdocu.kr:5000
WARNING! Using --password via the CLI is insecure. Use --password-stdin.
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded

 

로그인 성공하여 접근 허용이 되었으면, Registry 이미지 리스트를 확인합니다.

업로드한 이미지가 없기때문에 아직은 아무것도 출력되지 않습니다.

# curl -u sysdocu:12345678 https://registry.az1.sysdocu.kr:5000/v2/_catalog
{"repositories":[]}

 

여기까지 Registry 구축이 완료되었습니다.

아래는 다른 서버에서 Registry 를 사용하는 방법입니다.

 

 

4. 이미지 업로드 및 컨테이너 생성

 

두가지 방법이 있는데, 여기에서는 기본 컨테이너에서 내용을 변경해보는 아래 방식으로 진행합니다.

- Docker Hub 이미지 그대로 Registry 에 업로드

- Docker Hub 이미지를 받아서 수정하고 Registry 에 업로드

 

진행할 예제는 php:7.4-apache 기준으로 작성하였습니다.
우선 php:7.4-apache 이미지를 다운로드 합니다.

# docker pull docker.io/php:7.4-apache

 

테스트용으로 PHP 소스 파일을 만듭니다.

# mkdir ./source

# vi ./source/index.php

<?php
echo "Good job";
?>

 

Dockerfile 을 아래 내용으로 작성합니다.
# vi Dockerfile

FROM docker.io/php:7.4-apache
COPY ./source/ /var/www/html/
RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf
CMD ["apache2-foreground"]

 

* 설명

FROM docker.io/php:7.4-apache : 기본 이미지를 지정하는 부분입니다. php2.4 와 apache 웹서버가 설치된 이미지 입니다.
COPY ./source/ /var/www/html/ : 호스트 시스템의 ./source/ 디렉토리의 내용을 컨테이너 내부의 /var/www/html/ 디렉토리로 복사하는 명령입니다. 

RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf : Apache 웹서버에 ServerName 옵션을 추가합니다.
CMD ["apache2-foreground"] : 컨테이너가 시작될 때 실행될 명령입니다. 여기에서는 Apache 웹 서버를 시작합니다.

 

만들어진 Dockerfile 을 사용하여 Docker 이미지를 새로 만듭니다.

형식) docker build --tag <새 이미지 이름> <Dockerfile 위치>

# docker build --tag php7.4-apache-update .

 

만들어진 새 이미지가 확인 되었습니다.

# docker images
REPOSITORY             TAG       IMAGE ID       CREATED          SIZE
php7.4-apache-update   latest    b36ddfe193e1   28 seconds ago   453MB
registry               latest    0030ba3d620c   3 weeks ago      24.1MB

 

이번에는 로컬에 만들어져 있는 php7.4-apache-update 이미지를 Registry 에 올려 보겠습니다.

업로드 권한이 필요하므로 생성했던 htpasswd 계정을 이용해 Registry 에 로그인을 합니다.

(아까 위에서 로그인 했을 경우 생략 가능)

# docker login -u sysdocu -p 12345678 https://registry.az1.sysdocu.kr:5000

 

태그 설정을 하고 업로드 합니다.

태그 이름은 로컬에 만들어놓은 이름 (php7.4-apache-update) 과 동일하게 하겠습니다.

그리고 sysdocu 라는 디렉토리로 이미지 용도를 구분 짓도록 하겠습니다.

# docker tag php7.4-apache-update registry.az1.sysdocu.kr:5000/sysdocu/php7.4-apache-update

# docker push registry.az1.sysdocu.kr:5000/sysdocu/php7.4-apache-update
Using default tag: latest
The push refers to repository [registry.az1.sysdocu.kr:5000/sysdocu/php7.4-apache-update]
61323a0752b4: Pushed 
3d4722dde23c: Pushed 
3d33242bf117: Pushed 
529016396883: Pushed 
5464bcc3f1c2: Pushed 
28192e867e79: Pushed 
d173e78df32e: Pushed 
0be1ec4fbfdc: Pushed 
30fa0c430434: Pushed 
a538c5a6e4e0: Pushed 
e5d40f64dcb4: Pushed 
44148371c697: Pushed 
797a7c0590e0: Pushed 
f60117696410: Pushed 
ec4a38999118: Pushed 
latest: digest: sha256:2a03e9c0ac98d726ec0f6707d4bd6265aec6de5b0aa3b982315b9eaae0b61123 size: 3449

 

Registry 컨테이너 가동시 지정했던 로컬 호스트 디렉토리 /data 에서 컨테이너에 올려진 데이터가 확인됩니다.

# ll /data/docker/registry/v2/repositories/sysdocu/php7.4-apache-update/
total 20
drwxr-xr-x 5 root root 4096 Sep  6 02:26 ./
drwxr-xr-x 3 root root 4096 Sep  6 02:26 ../
drwxr-xr-x 3 root root 4096 Sep  6 02:26 _layers/
drwxr-xr-x 4 root root 4096 Sep  6 02:26 _manifests/
drwxr-xr-x 2 root root 4096 Sep  6 02:26 _uploads/

 

이렇게도 확인이 됩니다.

아까는 빈 내용이였던 Registry 에 업로드한 이미지가 확인됩니다.

# curl -u sysdocu:12345678 https://registry.az1.sysdocu.kr:5000/v2/_catalog
{"repositories":["sysdocu/php7.4-apache-update"]}

 

이제 업로드 된 이미지를 활용하여 애플리케이션을 구동할 수 있습니다.

방법은 두가지 형식이 있으며 여기에서는 간단히 Docker 컨테이너로 생성해 보겠습니다.

- Kubernetes (Openshift, K-PaaS 등) 에서 Pod 생성, Service 생성

- Docker 에서 컨테이너 생성

# docker run -d -p 80:80 registry.az1.sysdocu.kr:5000/sysdocu/php7.4-apache-update

 

* 설명
-d : 컨테이너를 백그라운드에서 실행합니다.
-p 80:80 : 호스트의 포트 80 을 컨테이너의 포트 80 으로 매핑합니다. 즉, 웹 서버가 동작하는 포트에 접근할 수 있게 됩니다.
registry.az1.sysdocu.kr:5000/sysdocu/php7.4-apache-update : 실행할 Docker 이미지를 지정합니다.

 

컨테이너가 실행되면 웹 서버가 시작되어 호스트의 IP 또는 도메인과 80 번 포트로 웹서버에 접속할 수 있게 됩니다.

# curl http://registry.az1.sysdocu.kr

Good job

 

반응형

댓글()

Kubernetes 1.28 에서 MetalLB 설치하기

반응형

MetalLB 를 설치하면 LoadBalancer 를 사용할 수 있는데, 이는 외부에서 접근하는 공인 IP 를 Pod 에 부여함으로써 온전히 애플리케이션의 포트를 NodePort (30000~32767) 와 같이 임의 포트가 아닌 공식 표준 포트를 사용할 수 있게 됩니다.

아래 예제의 Kubernetes 환경은 1.28 버전이며, 모든 명령은 master (control-plane) 서버에서 진행하였습니다.

 

공식 홈페이지 Documents : https://metallb.universe.tf/installation/

 

 

1. kube-proxy 구성 편집

 

kube-proxy 를 사용하는 경우 ARP 모드를 사용해야 합니다.

아래 명령을 이용해 kube-proxy 구성을 편집합니다.

# kubectl edit configmap -n kube-system kube-proxy
configmap/kube-proxy edited

...
ipvs:
  strictARP: true
...

 

위 내용으로 저장합니다.

 

 

2. MetalLB 설치

 

MetalLB 컴포넌트 등을 하나의 파일로 설치합니다. 작성일 기준 최신 버전은 0.13.10 입니다.

# kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.10/config/manifests/metallb-native.yaml

 

MetalLB 관련 Pod 가 잘 생성되었는지 확인합니다.

Running 상태까지 되는데 시간이 소요될 수 있습니다. (모든 Pod 1/1)

# kubectl get pod -n metallb-system
NAME                          READY   STATUS    RESTARTS   AGE
controller-5c6b6c8447-4kzpl   1/1     Running   0          15m
speaker-6fxtx                 1/1     Running   0          15m
speaker-7gg7s                 1/1     Running   0          15m
speaker-z284z                 1/1     Running   0          15m

 

 

3. IP Pool 생성

 

라우팅 처리를 하기위해 보유하고 있는 IP 리스트를 등록합니다.

Pod 에서 IP 를 사용할 수 있도록 상단 스위치단에서 IP 설정이 이루어져 있어야 합니다.

아래는 28비트 대역 2개를 추가해 보았습니다.

실제로 Pod 에 할당하려는 IP 범위를 적어줍니다.

# vi ippool.yaml

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: first-pool
  namespace: metallb-system
spec:
  addresses:
  - 115.68.142.130-115.68.142.140
  - 115.68.142.146-115.68.142.156

 

IP 를 추가할때는 서브넷 마스크를 별도로 지정하지 않아도 주소 범위 내의 모든 IP 주소를 사용할 수 있도록 인식합니다. MetalLB 는 주소 범위를 기반으로 자동으로 서브넷 마스크를 계산하기 때문입니다.

작성한 yaml 파일을 적용합니다.

# kubectl apply -f ippool.yaml

ipaddresspool.metallb.io/first-pool created

 

* 에러 발생시 ----------

여기에서 다음과 같은 에러가 발생했을때 조치방법 입니다.

Error from server (InternalError): error when creating "ippool.yaml": Internal error occurred: failed calling webhook "ipaddresspoolvalidationwebhook.metallb.io": failed to call webhook: Post "https://webhook-service.metallb-system.svc:443/validate-metallb-io-v1beta1-ipaddresspool?timeout=10s": dial tcp 10.102.110.54:443: connect: connection refused

 

이때는 아래와 같이 metallb-webhook-configuration 설정을 삭제하고 다시 실행해 보세요.

# kubectl delete validatingwebhookconfigurations metallb-webhook-configuration
validatingwebhookconfiguration.admissionregistration.k8s.io "metallb-webhook-configuration" deleted

----------------------------

 

L2 네트워크를 생성하고 적용합니다.

# vi l2.yaml

apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: my-l2
  namespace: metallb-system
spec:
  ipAddressPools:
  - first-pool

 

# kubectl apply -f l2.yaml

l2advertisement.metallb.io/my-l2 created

 

 

4. 테스트 (Pod 생성 및 IP 연결)

 

테스트를 위해 Nginx Pod 를 생성하고 공인 IP 를 할당하여 외부 통신이 되는지 확인합니다.

# kubectl create deploy nginx --image=nginx

deployment.apps/nginx created

 

# kubectl expose deploy nginx --port 80 --type LoadBalancer

service/nginx exposed

 

# kubectl get services
NAME         TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)        AGE
kubernetes   ClusterIP      10.96.0.1       <none>           443/TCP        3d
nginx        LoadBalancer   10.111.72.120   115.68.142.130   80:32088/TCP   20m

 

Kubernetes Cluster 외부의 네트워크에서 출력된 IP 로 접근하여 Nginx 가 열리는지 확인합니다.

# curl http://115.68.142.130

 

반응형

댓글()

Kubernetes 1.28 에서 worker 노드 제거 및 추가하기

반응형

1. 노드 제거하기

 

시스템 장애 또는 OS 재설치 등의 이유로 worker 노드 하나를 제거해야 할 수 있습니다.

제거하기 전의 Cluster 상태는 아래와 같습니다.

 

# kubectl get nodes
NAME      STATUS                     ROLES           AGE     VERSION
master    Ready                      control-plane   2d22h   v1.28.1
worker1   Ready                      <none>          2d22h   v1.28.1
worker2   Ready                      <none>          2d22h   v1.28.1

 

worker2 노드를 Kubernetes 클러스터에서 제거하고 다시 연결하는 프로세스는 다음과 같이 진행할 수 있습니다.
주의할 점이 하나 있는데, 노드를 클러스터에서 제거하면 해당 노드에서 실행 중인 모든 컨테이너와 Pod가 중지됩니다.

먼저 worker2 노드에서 실행 중인 Pod 를 다른 노드로 옮기거나 제거해야 합니다.

이 명령어는 worker2 노드에서 실행 중인 Pod 를 다른 노드로 옮기고, DaemonSet Pod 는 무시합니다.

# kubectl drain worker2 --ignore-daemonsets

node/worker2 cordoned
Warning: ignoring DaemonSet-managed Pods: kube-system/kube-proxy-8tqss
node/worker2 drained

 

이 상태로 node 리스트를 확인해보면, 해당 노드에 스케쥴링이 비활성화 된 것이 보입니다.

# kubectl get nodes
NAME      STATUS                     ROLES           AGE     VERSION
master    Ready                      control-plane   2d22h   v1.28.1
worker1   Ready                      <none>          2d22h   v1.28.1
worker2   Ready,SchedulingDisabled   <none>          2d22h   v1.28.1

 

worker2 노드를 클러스터 목록에서 제거합니다.
# kubectl delete node worker2

# kubectl get nodes
NAME      STATUS   ROLES           AGE     VERSION
master    Ready    control-plane   2d22h   v1.28.1
worker1   Ready    <none>          2d22h   v1.28.1

 

 

2. 노드 추가하기

 

worker2 노드를 다시 클러스터에 추가하려면 해당 노드를 다시 등록해야 합니다.

OS 를 재설치 한 경우 worker 노드의 환경 구성은 아래 URL 을 참고합니다.

https://sysdocu.tistory.com/1851

 

worker 노드 준비가 되었으면 master 서버에서 토큰 생성과 함께 join 명령을 출력합니다.

생성된 토큰의 유효 시간은 1일 (24시간) 이며, --ttl 1h 이런 옵션을 줄 경우 토큰 유효 시간을 지정할 수 있습니다.

(master 노드에서)

# kubeadm token create --print-join-command
kubeadm join 115.68.142.104:6443 --token pa3e56.88nw5c48vmbyr522 --discovery-token-ca-cert-hash sha256:82020f205bd07cd7b964a40227f33db5109adc523f042e742d7c6ec8443efbdc

 

(worker2 노드에서)

master 노드에서 출력된 명령줄을 실행합니다.

# kubeadm join 115.68.142.104:6443 --token pa3e56.88nw5c48vmbyr522 --discovery-token-ca-cert-hash sha256:82020f205bd07cd7b964a40227f33db5109adc523f042e742d7c6ec8443efbdc

 

추가된 worker2 노드를 확인합니다.

(master 노드에서)

# kubectl get nodes
NAME      STATUS   ROLES           AGE     VERSION
master    Ready    control-plane   2d23h   v1.28.1
worker1   Ready    <none>          2d23h   v1.28.1
worker2   Ready    <none>          3m44s   v1.28.1

 

* 에러 조치

master 서버에서 Pod 생성시 에러가 발생한다면 추가한 worker 노드에서 다음과 같이 조치 가능합니다.

 

[ 에러 ]

Events:
  Type     Reason                  Age                   From               Message
  ----     ------                  ----                  ----               -------
  Normal   Scheduled               37m                   default-scheduler  Successfully assigned ceph-csi-rbd/ceph-csi-rbd-nodeplugin-n9b2v to worker3
  Warning  FailedCreatePodSandBox  31m (x26 over 37m)    kubelet            Failed to create pod sandbox: rpc error: code = Unknown desc = cri-o configured with cgroupfs cgroup manager, but received systemd slice as parent: /kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-podd3fc3e78_f49c_4239_b271_55e406fd0b76.slice

 

[ 해결 ]

아래 kubelet 설정 파일에서 cgroup driver 를 바꿔줍니다.

(추가된 worker 노드에서)

# vi /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf

...

Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml --cgroup-driver=cgroupfs"
...

 

# systemctl daemon-reload
# systemctl restart kubelet

 

반응형

댓글()

Ubuntu 22.04 netplan 설정하기

리눅스/Network|2023. 9. 4. 13:50
반응형

Ubuntu 22.04 에서는 netplan 이 업데이트 되어 설정법이 약간 바뀌었습니다.

네트워크 설정 파일을 생성 합니다.

# vi /etc/netplan/50-cloud-init.yaml 

network:
  version: 2
  ethernets:
    eno1:
      addresses: [ 115.68.142.104/27 ]
      routes:
        - to: default
          via: 115.68.142.97
      nameservers:
        addresses: [ 8.8.8.8 ]

 

* 설명

eno1 : 네트워크 장치명입니다. 명칭을 모를경우 ip link 명령으로 확인이 가능합니다.

addresses : 비트수까지 기록해줘야 합니다. netmask 를 입력하는 곳이 없기 때문입니다.

routes: via : 게이트웨이 IP 를 입력합니다.

nameservers: addresses : 네임서버 IP 를 입력합니다.

 

설정을 적용합니다.

# netplan apply

 

 

 

 

 

 

 

반응형

댓글()

Ubuntu 22.04 에서 CRI-O, Kubernetes 1.28 Cluster, Calico 설치 및 애플리케이션 배포

반응형

Kubernetes 는 컨테이너의 생성, 배포, 실행을 하는 등 컨테이너를 관리하는 오픈소스 플랫폼 입니다.

여기에서는 Ubuntu 22.04 버전의 서버 3대로 (master 노드 1대 / worker 노드 2대) Kubernetes 1.28 을 구성하는 방법에 대해 설명합니다.

- 공식 Documents : https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/

 

 

1. CRI-O 설치

 

CRI-O 공식 홈페이지 : https://cri-o.io

 

Pod 를 실행하고 관리할 수 있도록 Containerd 나 CRI-O 와 같은 컨테이너 런타임을 설치해야 합니다.

여기에서는 CRI-O 를 설치하도록 하겠습니다.

 

(모든 노드에서)

서버별로 호스트네임을 설정하고 각 노드에 호스트명으로 통신 가능하도록 hosts 파일에 추가합니다.

# hostnamectl set-hostname master      // master 노드에서

# hostnamectl set-hostname worker1    // worker1 노드에서

# hostnamectl set-hostname worker2    // worker2 노드에서

# vi /etc/hosts

127.0.0.1 localhost
10.101.0.5 master
10.101.0.10 worker1
10.101.0.12 worker2

 

CRI-O 는 설치할 Kubernetes 버전과 동일한 버전으로 설치합니다.

(모든 노드에서)

# OS=xUbuntu_22.04
# VERSION=1.28

 

# echo "deb https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable.list
# echo "deb http://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/ /" > /etc/apt/sources.list.d/devel:kubic:libcontainers:stable:cri-o:$VERSION.list

# curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable:/cri-o:/$VERSION/$OS/Release.key | apt-key add -
# curl -L https://download.opensuse.org/repositories/devel:/kubic:/libcontainers:/stable/$OS/Release.key | apt-key add -

# apt -y update

# apt -y upgrade    // 설치중 묻는 질문에 기본값으로 답변

# apt -y install cri-o cri-o-runc cri-tools    // 설치중 묻는 질문에 기본값으로 답변

# systemctl enable --now crio

 

설치를 잘 마쳤으면 CRI-O 버전이 확인됩니다.

# crio version
crio version 1.28.0
Version:        1.28.0
GitCommit:      unknown
GitCommitDate:  unknown
GitTreeState:   clean
BuildDate:      2023-08-28T05:59:01Z
GoVersion:      go1.19
Compiler:       gc
Platform:       linux/amd64
Linkmode:       dynamic

...

 

 

2. Kubernetes 설치

 

Kubernetes 공식 홈페이지 : https://kubernetes.io

 

(모든 노드에서)

kubelet 사용을 위해 swap 을 반드시 비활성화 시켜줍니다.

# swapoff -a

# cat /etc/fstab

fstab 에서도 swap 파티션이 존재한다면 주석처리하여 비활성화 시킵니다.

 

이제 kubeadm, kubelet, kubectl 를 설치해야 하는데, 이 세가지는 모두 Kubernetes 클러스터 관리와 상호 작용을 위한 도구입니다.
- kubeadm : 클러스터를 부트스트랩하는 명령
- kubelet : 클러스터의 모든 노드에서 실행되는 POD와 컨테이너 시작과 같은 작업을 수행하는 컴포넌트
- kubectl : 클러스터와 통신하기 위한 CLI 유틸리티

 

패키지 저장소에서 파일을 안전하게 다운로드 받기 위해 아래 패키지를 설치합니다.

# apt -y install apt-transport-https ca-certificates

 

현재 기준 Kubernetes 최신 버전인 1.28 버전의 공용 서명 키를 다운로드합니다.

# curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.28/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg

 

Kubernetes Repository 를 추가합니다.

# echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.28/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list

 

APT 패키지 인덱스를 업데이트하고 kubelet, kubeadm, kubectl 을 설치합니다.

그리고 패키지가 자동으로 버전업 되지 않도록 고정합니다.

# apt -y update
# apt -y install kubelet kubeadm kubectl    // 설치중 묻는 질문에 기본값으로 답변
# apt-mark hold kubelet kubeadm kubectl

 

커널에 필요한 모듈을 로드 합니다.

(모든 노드에서)

# modprobe overlay
# modprobe br_netfilter

# cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF

 

sysctl 파라메타 값을 설정하고 리부팅 없이 적용합니다.
# cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
# sysctl --system

 

CRI-O는 기본적으로 systemd 라는 cgroup 드라이버를 사용합니다. 

(모든 노드에서)

# cat <<EOF | sudo tee /etc/crio/crio.conf.d/02-cgroup-manager.conf
[crio.runtime]
conmon_cgroup = "pod"
cgroup_manager = "systemd"
EOF

 

 

3. Cluster 생성

 

서버간 통신할 사설 네트워크 대역을 설정합니다.

현재 노드와 중복되지 않도록 새로운 대역으로 설정해 주었습니다.

- Nodes network : 10.101.0.0/24

- Pods network : 10.101.1.0/24

쿠버네티스 구성에 필요한 이미지를 다운로드 받아야 하므로 이 단계에서 시간이 약간 소요됩니다.

(master 노드에서)

# kubeadm init --pod-network-cidr=10.101.1.0/24

 

아래는 쿠버네티스 컨트롤 플레인이 성공적으로 초기화 되었을때 출력하는 메세지 입니다.

Your Kubernetes control-plane has initialized successfully!

To start using your cluster, you need to run the following as a regular user:

  mkdir -p $HOME/.kube
  sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
  sudo chown $(id -u):$(id -g) $HOME/.kube/config

Alternatively, if you are the root user, you can run:

  export KUBECONFIG=/etc/kubernetes/admin.conf

You should now deploy a pod network to the cluster.
Run "kubectl apply -f [podnetwork].yaml" with one of the options listed at:
  https://kubernetes.io/docs/concepts/cluster-administration/addons/

Then you can join any number of worker nodes by running the following on each as root:

kubeadm join 10.101.0.5:6443 --token w6ioaq.l37qcxuvs98q4n02 \
--discovery-token-ca-cert-hash sha256:bddfcfabe16f76edbb6a8af08a835ebf9defc67d902dd02091174e1bccacaa76

 

위에 나와있는 안내 대로 추가 명령을 실행하는데, 현재는 root 상태이므로 아래명령으로 Kubernetes 사용자 환경을 로드 합니다.

일반 사용자 상태로 진행을 원할 경우 위 안내된 mkdir 부분부터 세줄 명령을 실행하면 됩니다.

(master 노드에서)
# export KUBECONFIG=/etc/kubernetes/admin.conf

 

앞으로 SSH 접속시마다 자동으로 환경이 로드 되도록 하면 편리합니다.

# echo 'export KUBECONFIG="/etc/kubernetes/admin.conf"' >> ~/.bashrc

 

master 노드에서 확인 가능한 노드 상태를 출력합니다.

# kubectl get nodes
NAME     STATUS   ROLES           AGE   VERSION
master   Ready    control-plane   39s   v1.28.1

 

worker 노드에서는 아래와 같이 master 서버에 join (가입) 합니다.

token 과 hash 값은 쿠버네티스 컨트롤 플레인이 초기화 되었을때 출력된 값으로 합니다.

 

(모든 worker 노드에서)

# kubeadm join 10.101.0.5:6443 --token w6ioaq.l37qcxuvs98q4n02 \
--discovery-token-ca-cert-hash sha256:bddfcfabe16f76edbb6a8af08a835ebf9defc67d902dd02091174e1bccacaa76

 

다시 master 노드에서 확인 가능한 노드 상태를 출력하면 가입된 worker 노드 리스트까지 확인이 됩니다.

ROLES 부분이 아래와 같이 출력 되었는지 확인합니다.

(master 노드에서)

# kubectl get nodes
NAME      STATUS   ROLES           AGE     VERSION
master    Ready    control-plane   2m24s   v1.28.1
worker1   Ready    <none>          88s     v1.28.1
worker2   Ready    <none>          81s     v1.28.1

 

 

[참고 : Cluster 삭제]

 

이번에는 Cluster 를 삭제하는 방법을 안내합니다.

계속 Cluster 구성 진행을 원하시는 분은 이 부분을 건너뛰면 되고, 구성이 꼬이거나 처음부터 다시 하실 분만 참고하시면 됩니다.

 

(master 노드에서)

# kubeadm reset

# rm -r /etc/cni/net.d/*
# systemctl restart kubelet

 

(모든 worker 노드에서)

kubeadm join 명령을 하기 전에 아래 명령으로 기존 Cluster 정보를 삭제해야 합니다.

# kubeadm reset

# rm -rf /etc/kubernetes/*

# systemctl stop kubelet

 

 

4. Calico 설치

 

Calico 공식 홈페이지 : https://www.tigera.io/project-calico

 

Project Calico 는 Kubernetes에 대한 네트워크 정책 엔진입니다.
Calico 네트워크 정책 집행을 통해 네트워크 세분화 및 테넌트 격리를 구현할 수 있습니다.

 

1) Calico 설치하기

(master 노드에서)

Tigera Calico 연산자 및 사용자 지정 리소스 정의를 설치합니다.

현재 기준 Calico 최신버전은 3.26.1 입니다.
# kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/tigera-operator.yaml

필요한 커스텀 리소스를 생성하여 Calico 를 설치합니다.

배포하는 yaml 파일에서 CIDR 정보를 자신이 사용하는 네트워크 정보로 수정하고 생성합니다.

# wget https://raw.githubusercontent.com/projectcalico/calico/v3.26.1/manifests/custom-resources.yaml

# sed -i 's/192.168.0.0\/16/10.101.1.0\/24/' custom-resources.yaml 

# kubectl create -f custom-resources.yaml

다음 명령을 사용하여 모든 Pod 가 실행 중인지 확인합니다.

이 부분에서 모든 STATUS 값이 Running 이 되기까지 약간의 시간이 소요됩니다.

# kubectl get pods -n calico-system
NAME                                       READY   STATUS    RESTARTS   AGE
calico-kube-controllers-7fd8984cb7-b5t6n   1/1     Running   0          2m37s
calico-node-74bjg                          1/1     Running   0          2m37s
calico-node-8mrfw                          1/1     Running   0          2m37s
calico-node-9xn6h                          1/1     Running   0          2m37s
calico-typha-d4c4b7984-l4p5j               1/1     Running   0          2m37s
calico-typha-d4c4b7984-lc9hm               1/1     Running   0          2m31s
csi-node-driver-9lmnz                      2/2     Running   0          2m37s
csi-node-driver-hzt8h                      2/2     Running   0          2m37s
csi-node-driver-ljsds                      2/2     Running   0          2m37s

 

 

5. 애플리케이션 배포

 

볼륨을 포함한 애플리케이션을 배포하고 외부에서 접근하기 위한 네트워크 설정 및 도메인 연결 예제입니다.

 

1) Namespace

애플리케이션을 생성하고 배포할 작업공간을 생성하고 현재의 공간으로 변경해줍니다.

(master 노드에서)

# kubectl create ns sysdocu

# kubectl config set-context --current --namespace=sysdocu

 

2) Volume 생성

NFS, GlusterFS, Ceph 등 별도의 서버를 미리 구성하고 해당 공간을 할당받기 위해

PV (Persistent Volume) 와 PVC (Persistent Volume Claim) 를 생성하는 방법도 있지만,

여기에서는 Pod 가 배포된 worker 노드의 공간을 할애하는 hostPath 방법으로 진행해 보겠습니다.

hostPath 를 사용할 경우 디렉토리를 지정하는 것 외에 별도 작업은 없습니다.

html 데이터를 저장할 디렉토리를 생성합니다.

(모든 worker 노드에서)

# mkdir /html

 

3) Deployment 생성

Deployment 를 사용하면 Pod 생성 및 여러가지 옵션을 추가하여 다양한 구성이 가능합니다.

Deployment yaml 파일을 작성합니다.

(master 노드에서)

# vi deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
        - name: nginx
          image: nginx:latest
          ports:
            - containerPort: 80
          volumeMounts:
            - name: html-volume
              mountPath: /html/user001
      volumes:
        - name: html-volume
          hostPath:
            path: /usr/share/nginx/html
            type: DirectoryOrCreate

 

작성한 yaml 파일을 적용하여 생성합니다.

# kubectl apply -f deployment.yaml

deployment.apps/nginx-deployment created

 

Pod 가 자동 생성되는데, 아래와 같이 확인이 가능합니다.

# kubectl get pods
NAME                                READY   STATUS    RESTARTS   AGE
nginx-deployment-694db9fb84-b5h2r   1/1     Running   0          20s

 

4) Service 생성

네트워크 접근이 가능하도록 Service 를 생성해 줍니다.

테스트 목적이긴 하지만 외부 네트워크에서 접근이 되도록 해보겠습니다.

Service yaml 파일을 작성합니다.

# vi service.yaml

apiVersion: v1
kind: Service
metadata:
  name: nginx
spec:
  selector:
    app: nginx
  type: NodePort
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      nodePort: 30080  # 여기에 원하는 NodePort 값을 지정하세요. (범위 : 30000~32767)

 

* 참고

Service 에서 생성할 type 은 ClusterIP, NodePort, LoadBalancer 가 있습니다.

- ClusterIP : 클러스터 내부 통신만 가능한 IP

- NodePort : worker 노드의 IP 와 지정한 포트 (30000~32767 로 제한) 를 이용해 Pod 에 연결 가능

- LoadBalancer : 별도의 공인 IP 가 할당되고, 포트를 마음대로 사용 가능 (베어메탈 환경에서는 MetalLB 를 설치 필요)

 

작성한 yaml 파일을 적용하여 생성합니다.

# kubectl apply -f service.yaml

service/nginx created

 

Service 생성시 Endpoint 도 같이 생성되는데, 두가지 정보를 함께 출력해보면 아래와 같습니다.

# kubectl get services,ep

NAME    TYPE       CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
nginx   NodePort   10.110.222.108   <none>        80:30080/TCP   17s


NAME    ENDPOINTS        AGE
nginx   10.101.1.66:80   17s

 

외부 네트워크에서 접근되는지 확인합니다.

접근할 IP 는 Pod 가 위치하는 worker 노드인데, 아래 명령으로 확인 가능합니다.

# kubectl get pod -o wide

NAME                                READY   STATUS    RESTARTS   AGE     IP            NODE      NOMINATED NODE   READINESS GATES
nginx-deployment-694db9fb84-b5h2r   1/1     Running   0          7m22s   10.101.1.66   worker2   <none>           <none>

 

worker2 노드인것을 확인하였으며, 외부에서 worker2 노드의 공인 IP 와 위에서 설정한 포트 30080 으로 접근시 nginx 초기페이지가 출력되는것이 확인됩니다. 예제에서는 worker2 노드의 공인 IP 로 연결하였지만 실제로는 꼭 worker2 노드의 공인 IP 로 할 필요는 없습니다. NodePort 의 경우 master 또는 어떤 worker 노드로 연결하던 설정한 Pod 로 연결됩니다.

# curl 115.68.249.176:30080

 

5) Ingress 생성

Ingress 를 사용하면 도메인 연결이 가능합니다.

Ingress yaml 파일을 작성합니다.

# ingress.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: nginx
  namespace: sysdocu
spec:
  rules:
  - host: nginx.sysdocu.kr    # 사용할 도메인
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx    # 연결할 Service 이름
            port:
              number: 80    # 연결할 Service 포트 번호

 

작성한 yaml 파일을 적용합니다.

# ingress.networking.k8s.io/nginx created

 

Ingress 가 생성되었습니다.

# kubectl get ingress
NAME    CLASS    HOSTS              ADDRESS   PORTS   AGE
nginx   <none>   nginx.sysdocu.kr             80      30s

 

사용할 도메인 (nginx.sysdocu.kr) 은 DNS 에서 IP 를 worker 노드의 IP 로 미리 등록해 놓아야 합니다.

아래와 같이 접속이 확인되었습니다.

# curl nginx.sysdocu.kr:30080

 

nginx 와 같은 웹서버에서 사용하는 포트는 보통 80 또는 443 이지만, NodePort 사용시 번거롭게 30000~32767 사이의 포트 번호를 사용해야 연결이 됩니다. 포트 번호없이 도메인만으로 접속을 원하는 경우 MetalLB 를 구성해 공인 IP 를 할당해 주면 됩니다.

- MetalLB 설치 : https://sysdocu.tistory.com/1854

 

 

 

 

반응형

댓글()

오픈 클라우드 플랫폼 K-PaaS (구 PaaS-TA) 6.5 Container Platform Portal 사용하기

리눅스/PaaS|2023. 8. 9. 10:40
반응형

본 문서는 공식 Documents 를 참고하여 실습한 후 작성된 내용으로 구성되어 있습니다.

https://github.com/PaaS-TA/paas-ta-container-platform/blob/master/use-guide/portal/container-platform-portal-guide.md

 

컨테이너 플랫폼 포털 URL 은 master 서버 (IP 또는 호스트명) 와 포트 32703 을 이용해 접근이 가능합니다.

http://115.68.142.67:32703

 

 

1. 일반 사용자 추가

 

컨테이너 플랫폼 포털 (이하 '포털') 로그인 화면에서 하단의 'Register' 버튼을 눌러 회원가입을 합니다.

회원가입시 Username 은 로그인 아이디에 해당 되는 부분이므로 영문 작성을 하면 되고, [Register] 버튼을 눌러 가입하면 '관리자의 승인이 필요' 하다는 메세지가 출력됩니다.

 

관리자는 승인을 기다리는 계정에 Namespace (프로젝트) 를 생성 후 Role (권한) 부여를 해주어야 합니다.

테스트 목적으로 아래와 같이 설정하였습니다.

 

1) Namespace 및 Role 생성

위치 : Clusters > Namespaces 화면에서 [생성] 버튼 클릭

> Name : mynamespace 입력 (소문자로만 입력해야 합니다)

> Resource Quotas : cp-low-resourcequota 선택

> Limit Ranges : cp-low-limitrange 선택

> [저장] 버튼을 눌러 생성합니다.

 

2) Namespace 및 Role 할당

위치 : 포털 로그인 > Managements > Users > 'User' 탭 > '비활성' 탭 클릭

> 사용자 계정을 클릭 후, 하단 [수정] 버튼을 누릅니다.

> Authority : [User] 로 선택합니다.

> Namespaces ⁄ Roles 옆에 [선택] 클릭합니다.

> 위에서 생성했던 mynamespace (cp-admin-role) 체크 > [선택 완료] > [수정]

 

이제 계정이 활성 처리 되었습니다.

admin 을 로그아웃하고 일반 사용자 계정으로 로그인합니다.

 

 

2. 응용프로그램 배포

 

admin 계정으로는 모든 메뉴의 권한이 열려 있기 때문에 K-PaaS 에서 제공하는 기능을 모두 사용할 수 있습니다.

여기에서는 위에서 생성했던 일반 사용자 계정으로 응용프로그램을 배포하는 과정을 설명하겠습니다.

 

1) Deployment 생성

컨테이너를 다운로드 받고 응용프로그램을 배포할 수 있습니다.

위치 : 포털 로그인 > Workloads > Deployments

> [생성] 버튼을 누릅니다.

> YAML 입력창에 아래 내용을 작성하고 [저장] 버튼을 누릅니다.

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx-deployment
  labels:
    app: nginx
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - name: nginx
        image: nginx
        ports:
        - containerPort: 80

 

저장과 동시에 자동으로 yaml 설정값이 적용되며, Deployments 는 물론이고 Pods 와 ReplicaSets 메뉴에서도 관련 정보가 확인됩니다.

 

2) Services 생성

서비스를 NodePort 형식으로 생성하면 외부에서 응용 프로그램으로 연결이 가능해집니다.

위치 : 포털 로그인 > Services > Services

> [생성] 버튼을 누릅니다.

> YAML 입력창에 아래 내용을 작성하고 [저장] 버튼을 누릅니다.

apiVersion: v1
kind: Service
metadata:
  name: nginx-service
spec:
  selector:
    app: nginx
  type: NodePort
  ports:
  - name: nginx-port
    nodePort: 30001
    port: 80
    targetPort: 80

 

* Port 설명

- nodePort: 외부 네트워크에서 접속하는 포트 번호 입니다. (30000~32767 사이의 포트 번호를 사용) 이 포트는 Service Port 로 연결됩니다.

- port: Service 의 포트 번호 입니다. 이 포트는 targetPort 로 연결됩니다.

- targetPort: Pod 의 포트 입니다.

- 기본 80 포트 연결을 원할 경우 type 을 LoadBalancer 로 변경해야 합니다.

 

3) Ingresses 생성

개인이 소유하고 있는 도메인을 사용하는 방법입니다.

위치 : 포털 로그인 > Services > Ingresses

> [생성] 버튼을 누릅니다.

> Name : myingress 입력 (소문자로만 입력해야 합니다)

> Host : test.sysdocu.kr 입력 (네임서버 설정 IP 는 master node, worker node 어느것이든 상관 없습니다)

> Path : Prefix 선택, / 입력

> Target : 위에서 생성했던 Service 명, Port : 80 입력

> [저장] 버튼을 누릅니다.

 

4) 응용프로그램 접속

웹브라우저를 통해 준비된 도메인과 포트번호로 접근하면 웹서버 기본페이지가 출력됩니다.

http://test.sysdocu.kr:30001

 

5) 볼륨 추가

외부 스토리지의 일정 용량을 할당 받아 Pod 에 연결하는 방법입니다.

위치 : 포털 로그인 > Persistent Volume Claims

> [생성] 버튼을 누릅니다.

> YAML 입력창에 아래 내용을 작성하고 [저장] 버튼을 누릅니다.

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: nginx-pvc
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

 

볼륨을 위에서 생성했던 Pod 에 붙여 보겠습니다.

위치 : 포털 로그인 > Workloads > Deployments

> Deployments 이름 선택

> 아래 [수정] 버튼을 누릅니다.

> YAML 입력창에 아래 파란색으로 표시한 내용을 추가하고 [저장] 버튼을 누릅니다.

...

        terminationMessagePolicy: File
        volumeMounts:
        - mountPath: /backup
          name: my-pvc
      dnsPolicy: ClusterFirst

...

      terminationGracePeriodSeconds: 30
      volumes:
      - name: my-pvc
        persistentVolumeClaim:
          claimName: nginx-pvc
status:

...

 

Deployment 를 수정하면 Pod 가 재생성 됩니다.

Pod 이름을 확인하고, Pod bash 쉘에 진입하여 파티션을 확인합니다.

$ kubectl get pod -n mynamespace
NAME                               READY   STATUS    RESTARTS   AGE
nginx-deployment-b5cd59b6c-zj7pg   1/1     Running   0          1m33s

 

$ kubectl exec -it nginx-deployment-b5cd59b6c-zj7pg -n mynamespace -- /bin/bash

# df -h
Filesystem                                                                        Size  Used Avail Use% Mounted on
overlay                                                                            20G   11G  8.9G  54% /
tmpfs                                                                              64M     0   64M   0% /dev
tmpfs                                                                             3.9G     0  3.9G   0% /sys/fs/cgroup
shm                                                                                64M     0   64M   0% /dev/shm
tmpfs                                                                             795M  5.0M  790M   1% /etc/hostname
172.16.1.32:/data/mynamespace-nginx-pvc-pvc-4bde4a92-4288-415f-bba7-ca99bf4fb7fe   20G  2.7G   18G  14% /backup
/dev/vda1                                                                          20G   11G  8.9G  54% /etc/hosts
tmpfs                                                                             500M   12K  500M   1% /run/secrets/kubernetes.io/serviceaccount
tmpfs                                                                             3.9G     0  3.9G   0% /proc/acpi
tmpfs                                                                             3.9G     0  3.9G   0% /proc/scsi
tmpfs                                                                             3.9G     0  3.9G   0% /sys/firmware

 

* 참고

PVC 를 1G 로 설정했는데, 20G 로 보이는 이유는 NFS 를 PV (Persistent Volume) 로 사용하기 때문입니다.

NFS 에서는 계정별 Quota 설정이 없으므로 공유디렉토리 총 사용량이 출력됩니다.

할당받은 용량으로 보이길 원할 경우 Ceph, ISCSI, GlusterFS 등 용량 개별 할당이 가능한 PV 로 사용하는 방법이 있습니다.

 

6) ConfigMaps

ConfigMap 은 어플리케이션의 환경 설정 정보나 구성 값들을 분리하여 저장하는 리소스입니다. 이를 통해 설정 값들을 어플리케이션 코드와 분리하여 관리하고, 환경별로 다른 설정을 제공하거나 변경 사항을 쉽게 적용할 수 있습니다.

 

다음은 ConfigMap 의 database-url 설정 값을 DATABASE_URL 환경 변수로 설정하여 Pod 에서 사용하는 예시 입니다. 이렇게 설정한 값이 Pod 내의 환경 변수로 주입되어 어플리케이션에서 사용할 수 있습니다.

위치 : 포털 로그인 > ConfigMaps > ConfigMaps

> [생성] 버튼을 누릅니다.

> YAML 입력창에 아래 내용을 작성하고 [저장] 버튼을 누릅니다.

apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config
data:
  database-url: "mysql://sysdocu:12345678@db.sysdocu.kr/testdb"

 

그리고 Pod 에서 ConfigMap 을 사용할 수 있도록 Deployment 설정을 수정해줍니다.

위치 : 포털 로그인 > Workloads > Deployments

> Deployments 이름 선택

> 아래 [수정] 버튼을 누릅니다.

> YAML 입력창에 아래 파란색으로 표시한 내용을 추가하고 [저장] 버튼을 누릅니다.

...

      containers:
      - image: nginx
        imagePullPolicy: Always
        env:
          - name: DATABASE_URL
            valueFrom:
              configMapKeyRef:
                name: my-config
                key: database-url
        name: nginx

...

 

Pod 에서 변수를 확인해보겠습니다.

Pod 이름을 확인하고, Pod bash 쉘에 진입하여 변수를 잘 받아왔는지 확인합니다.

$ kubectl get pod -n mynamespace
NAME                               READY   STATUS    RESTARTS   AGE
nginx-deployment-799d57d87-zwjsz   1/1     Running   0          25s

 

$ kubectl exec -it nginx-deployment-799d57d87-zwjsz -n mynamespace -- /bin/bash

# echo $DATABASE_URL
mysql://sysdocu:12345678@db.sysdocu.kr/testdb

 

7) Managements

Managements 에서는 아래 기능 설정이 가능합니다.

- Roles : 작업에 대한 권한을 정의

- Resource Quotas : 네임스페이스 내의 모든 Pod, 리소스 및 객체의 사용량을 관리

- Limit Ranges : 컨테이너 및 Pod의 리소스 사용을 제한하는 데 사용

 

따로 필요한 부분만 설정하여 사용이 가능하지만 여기 예제에서는 한 번에 설정하고 적용하도록 하겠습니다.

아래 설정값을 먼저 작성해둡니다.

위치 : 포털 로그인 > Managements > Roles

> [생성] 버튼을 누릅니다.

> YAML 입력창에 아래 내용을 작성하고 [저장] 버튼을 누릅니다.

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: mynamespace
  name: my-role
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]

 

my-role 이라는 Role 에 pods 리소스에 대한 get, list, watch 명령을 수행할 수 있는 권한을 주었습니다.

이어서 Resource Quotas 를 작성합니다.

 

위치 : 포털 로그인 > Managements > Resource Quotas

> [생성] 버튼을 누릅니다.

> YAML 입력창에 아래 내용을 작성하고 [저장] 버튼을 누릅니다.

apiVersion: v1
kind: ResourceQuota
metadata:
  namespace: mynamespace
  name: my-resource-quota
spec:
  hard:
    pods: "5"
    requests.cpu: "1"
    requests.memory: 1Gi
    limits.cpu: "2"
    limits.memory: 2Gi

 

my-resource-quota 라는 Resource Quota 는 네임스페이스 내에서 최대 5개의 Pod 를 생성하며, CPU 및 메모리에 대한 요청과 제한 값을 설정하였습니다.

 

* 참고 : 권한 상승

YAML 저장시 "해당 리소스에 접근할 수 있는 권한이 없습니다." 라는 메세지가 출력될 경우, 포털 admin 계정으로 현재 계정에 대해 권한을 상승시켜주면 됩니다.

위치 : admin 계정으로 포털 로그인 > Managements > Users > 'User' 탭

> 사용자 계정을 클릭 후 하단 [수정] 버튼을 누릅니다.

Authority : [Cluster Admin] 으로 변경 후 [저장] 버튼을 누릅니다.

> admin 계정을 로그아웃 하고 다시 일반 계정으로 로그인합니다.

> 위 Resource Quota 를 생성합니다.

 

이어서 Limit Ranges 를 작성합니다.

위치 : 포털 로그인 > Managements > Limit Ranges

> [생성] 버튼을 누릅니다.

> YAML 입력창에 아래 내용을 작성하고 [저장] 버튼을 누릅니다.

apiVersion: v1
kind: LimitRange
metadata:
  namespace: mynamespace
  name: my-limit-range
spec:
  limits:
  - type: Container
    max:
      memory: 500Mi
    default:
      memory: 100Mi
    defaultRequest:
      memory: 50Mi

 

my-limit-range 라는 Limit Range 를 생성하여 컨테이너의 메모리에 대한 제한과 요청 값을 설정하였습니다.

 

Resource Quota, Limit Range 는 네임스페이스 내에서 생성해 두기만 하면 이후에 생성되는 Pod 에 자동 적용이 됩니다.

그리고 Role 은 일반적으로 Kubernetes 환경에서 사용하려면 Role Binding 과 ServiceAccount 를 추가로 생성해서 Deployment 에 연결시켜줘야 하지만, K-PaaS 에서는 Role 을 만들고 admin 계정으로 특정 계정의 Namespace 와 Role 을 선택해 주기만 하면 됩니다.

위에서 미리 생성했던 Role 을 계정에 적용해 보겠습니다.

우선, 일반 계정을 로그아웃 하고 admin 계정으로 로그인 합니다.

위치 : 포털 로그인 > Managements > Users

> 'Administrator' 탭에서 계정 이름 선택

> 아래 [수정] 버튼을 누릅니다.

> Authority 값을 Cluster Admin 에서 User 로 변경하고

> 바로 아래에 있는 Namespaces ⁄ Roles 의 [선택] 버튼을 누릅니다.

> 만들었던 Namespace 와 Role 을 선택합니다. (예 : mynamespace / my-role)

> [선택 완료] 버튼을 누릅니다.

> 하단의 [수정] 버튼을 누릅니다.

 

일반 계정에 권한이 적용되었습니다.

절차에서 알 수 있듯이 admin 계정이나 Cluster Admin 권한의 계정은 Role 적용이 되지 않습니다.

 

반응형

댓글()

iptables 명령으로 특정대역 22번 포트 허용 및 모두 차단

리눅스/Network|2023. 7. 31. 12:22
반응형

* 주의 : 룰에서 설정하는것이 아닌 iptables 명령을 통한 것이므로 리부팅이나 데몬 재시작시 룰이 초기화 되어 집니다.

 

iptables를 사용하여 22번 포트를 특정 대역에서만 열고 모두 차단하는 방법은 다음과 같습니다.
# iptables -A INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT
# iptables -A INPUT -p tcp --dport 22 -j DROP

 

위의 명령을 실행하면, 192.168.1.0/24 대역에서 오는 SSH (22번 포트) 접근은 허용되고, 나머지 모든 IP 주소에서 오는 SSH 접근은 차단됩니다.

기존의 규칙이 있다면 -I 옵션을 사용해서 적용해야 합니다.

# iptables -I INPUT -p tcp --dport 22 -s 192.168.1.0/24 -j ACCEPT
# iptables -A INPUT -p tcp --dport 22 -j DROP

반응형

댓글()

Ubuntu 20.04 기본 방화벽 변경하기 (ufw -> iptables)

리눅스/Network|2023. 7. 27. 13:57
반응형

기본 방화벽을 중지합니다.
# systemctl disable --now ufw

iptables 를 설치합니다.

# apt-get -y update
# apt-get -y install iptables-persistent
(설치중 물음에는 'Yes' 로 대답)

 

룰 파일 위치는 아래와 같습니다.

여기에서는 예시로 작성했으니 서버 상황에 맞게 수정해서 사용하시면 됩니다.

# vi /etc/iptables/rules.v4

*filter
:INPUT DROP [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]

# Loopback 트래픽은 항상 허용합니다.
-A INPUT -i lo -j ACCEPT
-A OUTPUT -o lo -j ACCEPT

# ICMP 를 허용합니다.
-A INPUT -p icmp -m icmp --icmp-type any -j ACCEPT

# 특정 IP 주소에서 모든 포트로 들어오는 트래픽을 허용합니다.
-A INPUT -s 192.168.10.2 -p tcp -j ACCEPT
-A INPUT -s 172.16.1.0/24 -p tcp -j ACCEPT

# 이미 연결된 세션은 허용합니다.
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# 모든 아이피에서 포트 80번으로 들어오는 연결을 허용합니다.
-A INPUT -p tcp --dport 80 -j ACCEPT

COMMIT

 

iptables 가동하고, 부팅시 자동 실행되도록 합니다.

# systemctl enable --now iptables

 

적용된 iptables 룰을 확인합니다.

# iptables -nL

 

반응형

댓글()