$ sudo yum install epel-release
$ sudo yum install ansible
## Adding Ansible command shell completion
## -> 이것은 편의를 위한 기능이니, 꼭 설치할 필요는 없다
$ sudo yum install python-argcomplete
$ sudo activate-global-python-argcomplete
## Let's check the version
$ ansible --version
ansible 2.9.25
...
## host inventroy file을 편집
$ cat /etc/ansible/hosts
...
[kubeworker]
10.10.12.64
10.10.12.71
[mynode]
10.10.12.64
...
$
##
## TEST for installation
##
$ ansible all --list-hosts
hosts (2):
10.10.12.64
10.10.12.71
$ ansible all -m ping
10.10.12.64 | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python"
},
"changed": false,
"ping": "pong"
}
10.10.12.71 | UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: ssh: connect to host 10.10.12.71 port 22: No route to host",
"unreachable": true
}
$
Run example playbook - 1
##
## Run this playbook on control node
##
$ cat playbook-example.yaml
---
- name: Add_sample_contents_to_file
hosts: mynode
tasks:
- name: Add sample contents to file
blockinfile:
path: /root/sample_a.txt
block: |
[my test section]
best contents
greeting=hello
$
$ ansible-playbook playbook-example.yaml
PLAY [Add_sample_file] ************************************************************************************************************
TASK [Gathering Facts] ************************************************************************************************************
ok: [10.10.12.64]
TASK [Add sample file] ************************************************************************************************************
changed: [10.10.12.64]
PLAY RECAP ************************************************************************************************************************
10.10.12.64 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
$
##
## Check result of test on managed node(10.10.12.64)
##
$ cat /root/sample_a.txt
# BEGIN ANSIBLE MANAGED BLOCK
[my test section]
best contents
greeting=hello
# END ANSIBLE MANAGED BLOCK
$
Run example playbook - 2
##
## Run this playbook on control node
##
$ cat playbook-example-2.yaml
---
- name: Install pkg and create a file
hosts: mynode
tasks:
- name: Install kubernetes pkg
yum: name=tree state=present
when: ansible_distribution == 'CentOS'
- name: Run my command
command: "touch /root/mydate.txt"
when: ansible_distribution == 'CentOS'
$
$ ansible-playbook playbook-example-2.yaml
...
$
##
## Check result of test on managed node(10.10.12.64)
##
$ which tree
/usr/bin/tree
$ ls /root/mydate.txt
/root/mydate.txt
Tip: 특정 User로 Ansible 실행
managed node에서 특정 user(예: root)로 실행되길 원한다면, 아래와 같이 설정 파일을 작성한다.
$ cat /etc/ansible/ansible.cfg
...
[privilege_escalation]
become=True
become_method=sudo
become_user=root ## Root user로 명령을 수행한다.
become_ask_pass=False ## password를 묻지 않고 명령을 수행한다.
...
$
## TFTP 서버의 /var/lib/tftpboot/pxelinux.cfg/default 파일에 아래와 같은 내용을 작성한다.
$ cat /var/lib/tftpboot/pxelinux.cfg/default
default menu.c32
prompt 0
timeout 30
menu title Homelab PXE Menu
label centos7_x64
menu label CentOS 7_X64
kernel /networkboot/centos/vmlinuz
append initrd=/networkboot/centos/initrd.img inst.repo=ftp://10.10.12.33/pub/centos ks=ftp://10.10.12.33/pub/centos/centos7.cfg
Linux OS image file 준비
## FTP server에 Linux OS image file을 복사하는 절차
$ mkdir /media/iso
$ mount /myhome/CentOS-7-x86_64-2009.iso /media/iso
$ mkdir -p /var/ftp/pub/centos
$ cp -r /media/iso/* /var/ftp/pub/centos/
## 준비 작업을 마무리했다면, FTP 서버에 접근 가능한지 아래와 같이 확인한다.
## (가능하면 Remote Node에서 테스트할 것)
$ curl ftp://x-node.hub.cncf/pub/centos/
-rw-r--r-- 1 0 0 14 Oct 29 2020 CentOS_BuildTag
drwxr-xr-x 3 0 0 35 Oct 26 2020 EFI
-rw-rw-r-- 1 0 0 227 Aug 30 2017 EULA
-rw-rw-r-- 1 0 0 18009 Dec 09 2015 GPL
drwxr-xr-x 2 0 0 43 Oct 26 2020 LiveOS
drwxr-xr-x 2 0 0 225280 Nov 04 2020 Packages
-rw-rw-r-- 1 0 0 1690 Dec 09 2015 RPM-GPG-KEY-CentOS-7
-rw-rw-r-- 1 0 0 1690 Dec 09 2015 RPM-GPG-KEY-CentOS-Testing-7
-r--r--r-- 1 0 0 2883 Nov 04 2020 TRANS.TBL
-rwxr-xr-x 1 0 0 1833 Nov 09 10:16 centos7-graphical-server.cfg
-rwxr-xr-x 1 0 0 1708 Nov 10 14:37 centos7-ok-11-10.cfg
-rwxr-xr-x 1 0 0 5462 Nov 11 10:16 centos7-ok-11-11-2nd.cfg
-rwxr-xr-x 1 0 0 3381 Nov 11 01:39 centos7-ok-11-11.cfg
-rwxr-xr-x 1 0 0 5633 Nov 11 16:14 centos7-ok-11-12.cfg
-rwxr-xr-x 1 0 0 5739 Nov 12 03:09 centos7.cfg
drwxr-xr-x 3 0 0 57 Oct 26 2020 images
drwxr-xr-x 2 0 0 198 Nov 02 2020 isolinux
drwxr-xr-x 2 0 0 4096 Nov 04 2020 repodata
centos7.cfg 파일의 내용이 길어서 보기 어려울 수 있으나, 원래 OS 패키지에 기본 제공되는 centos7.cfg에 일부 내용만 수정하면 된다.
(참고: /root/centos7.cfg 같은 곳에 OS 배포판에서 제공하는 기본 kickstart configuration 파일이 있다)
$ cat /var/ftp/pub/centos/centos7.cfg
## System authorization information
auth --enableshadow --passalgo=sha512
## Andrew
## Use network installation
url --url="ftp://10.10.12.33/pub/centos/"
## Use graphical install
#graphical
text
## Run the Setup Agent on first boot
firstboot --enable
ignoredisk --only-use=vda
## Keyboard layouts
keyboard --vckeymap=us --xlayouts='us'
## System language
lang en_US.UTF-8
## Network information
network --bootproto=dhcp --device=eth0 --nameserver=10.10.12.2,10.10.12.3 --noipv6 --activate
## Root user's password
## NOTE: Run this command `openssl passwd -1 mysmilepass`
## and use the result string as a password for user.
rootpw --iscrypted $1$HC34jk4576jk23j4kljk5l6jk2j345kj
## System services
services --disabled="chronyd"
## System timezone
timezone Asia/Seoul --isUtc --nontp
## NOTE: Run this command `openssl passwd -1 myhappypass`
## and use the result string as a password for user.
user --groups=wheel --name=sejong --password=$1$HC34jk4576jk23j4kljk5l6jk2j345kj --iscrypted --uid=1000 --gecos="sejong" --gid=1000
## X Window System configuration information
#xconfig --startxonboot
## System bootloader configuration
bootloader --append=" crashkernel=auto" --location=mbr --boot-drive=vda
autopart --type=lvm
## Partition clearing information
clearpart --all --initlabel --drives=vda
## Install software application
%packages
@^minimal
@base
@core
kexec-tools
net-tools
chrony
%end
## Enable KDUMP
%addon com_redhat_kdump --enable --reserve-mb='auto'
%end
## Policy of user password
%anaconda
pwpolicy root --minlen=6 --minquality=1 --notstrict --nochanges --notempty
pwpolicy user --minlen=6 --minquality=1 --notstrict --nochanges --emptyok
pwpolicy luks --minlen=6 --minquality=1 --notstrict --nochanges --notempty
%end
##
## NOTE (By Andrew)
## Refer to https://docs.centos.org/en-US/centos/install-guide/Kickstart2/#sect-kickstart-postinstall
##
%post --interpreter=/bin/bash
## NOTE (By Andrew)
myhostname=$(nslookup $(hostname -I | awk '{print $1}') 10.10.12.30 | awk '{print $4}' | cut -d '.' -f1)
hostname $myhostname
echo $myhostname > /etc/hostname
## Add authorized_keys for root user
mkdir --mode=0700 /root/.ssh
cat << EOF > /root/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yaskdjfkjk34634jkdkfjg.....= sejong@MacBook-Pro.local
EOF
chown -R root:root /root/.ssh
chmod 0600 /root/.ssh/authorized_keys
## Add authorized_keys for sejong user
mkdir --mode=0700 /home/sejong/.ssh
cat << EOF > /home/sejong/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yaskdjfkjk34634jkdkfjg.....= sejong@MacBook-Pro.local
EOF
chown -R sejong:sejong /home/sejong/.ssh
chmod 0600 /home/sejong/.ssh/authorized_keys
##
## Install Docker, Kubernetes
##
modprobe br_netfilter
cat <<EOF | tee /etc/modules-load.d/k8s.conf
br_netfilter
EOF
cat <<EOF | tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
EOF
sysctl --system
## disable swap space
sed -i '/swap/d' /etc/fstab
swapoff -a
## disable firewalld
systemctl stop firewalld
systemctl disable firewalld
## Install Docker container runtime
yum install -y yum-utils
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce docker-ce-cli containerd.io
systemctl enable docker
systemctl start docker
mkdir -p /etc/docker
cat <<EOF | tee /etc/docker/daemon.json
{
"exec-opts": ["native.cgroupdriver=systemd"],
"log-driver": "json-file",
"log-opts": {
"max-size": "100m"
},
"storage-driver": "overlay2",
"insecure-registries": ["myhost.cncf:8080", "yourhost.cncf:8080"]
}
EOF
systemctl daemon-reload
systemctl restart docker
## Install kubeadm, kubelete
cat <<EOF | tee /etc/yum.repos.d/kubernetes.repo
[kubernetes]
name=Kubernetes
baseurl=https://packages.cloud.google.com/yum/repos/kubernetes-el7-\$basearch
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=https://packages.cloud.google.com/yum/doc/yum-key.gpg https://packages.cloud.google.com/yum/doc/rpm-package-key.gpg
exclude=kubelet kubeadm kubectl
EOF
setenforce 0
sed -i 's/^SELINUX=enforcing$/SELINUX=permissive/' /etc/selinux/config
yum install -y kubelet kubeadm kubectl --disableexcludes=kubernetes
systemctl enable --now kubelet
chmod +x /etc/rc.d/rc.local
systemctl enable --now rc-local.service
echo "END OF POST-SCRIPT" > /root/kickstart.log
%end
## Andrew
## reboot after finishing installation
reboot
Ansible Playbook 작성 (Option)
만약, kickstart configration만으로 OS 초기화/설정하기 어려운 복잡한 Job이 있다면, 아래 예시처럼 Ansible playbook을 작성해서 좀 더 복잡하고 지능적인 처리가 가능하다.
## playbook-kube-cluster-join.yaml
- name: Joining Job Step 1 on Master node
hosts: kubemaster
tasks:
- name: Generate join command
command: kubeadm token create --print-join-command
register: join_command
- name: Copy join command to local file
local_action: copy content="{{ join_command.stdout_lines[0] }}" dest="./join-command"
- name: Joining Job Step 2 on Worker node
hosts: kubeworker
tasks:
- name: Copy the join command to server location
copy: src=join-command dest=/tmp/join-command.sh mode=0777
- name: Join the node to cluster
command: sh /tmp/join-command.sh
준비 작업은 끝났다.
공장 초기화된 컴퓨터, 또는 VirtualBox 프로그램, 또는 KVM/Qemu의 Virtual Manager로 아래 예제처럼 Machine Start만 하면 된다.
OS 자동 설치 실행
나는 KVM/Qemu + Virtual Manager 조합으로 VM을 만드는 것을 좋아하기 때문에 KVM을 예시로 들었다.
Hypervisor는 어떤 것을 사용하든 PXE로 부팅하는 기능은 동일하기 때문에, 다른 Hypervisor를 사용하더라도 아래 절차는 비슷하다.
깡통 컴퓨터의 Booting Option 메뉴에서 또는 VM을 새로 생성하면서 PXE 옵션을 선택한다.
위와 같이 PXE boot 옵션을 선택 후, booting을 시도하면 아래 화면처럼 DHCP 서버에서 Network 주소 및 TFTP 정보를 가져와서 TFTP에서 boot image file을 가져온다. 이후부터는 자동으로 OS를 설치하고, kickstart confiration file에 있는 OS 설정 작업을 자동 수행한다.
Reference
'청년정신'님이 2019년 4월에 작성한 'PXE 기반의 CentOS 자동 구축' 블로그가 제일 잘 정리된 글 같다.
PXE 기반의 CentOS 설치 1부
PXE 기반의 CentOS 설치 2부
추가로, CentOS를 kickstart를 이용해서 자동 설치하려는 경우라면, 아래 Install guide를 참고하면 좋다.
이런 경우 cut 명령, awk 명령을 이용해서 아래 예제와 같이 문자열에서 원하는 부분을 분리(split, delimit)할 수 있다.
cut 명령 예제
## 예들 들어, "aa.bb.cc." 라는 문자열이 있다면,
## 아래와 같이 실행하면, "aa"만 뽑을 수 있다.
$ echo "aa.bb.cc." | cut -d '.' -f1
aa
$ echo "aa.bb.cc." | cut -d '.' -f2
bb
$ echo "aa.bb.cc." | cut -d '.' -f3
cc
$
테스트한 날짜: 2024년 2월 15일 테스트 환경: Ubuntu 22.04 / Ubuntu 20.04 / Ubuntu 18.04 (이 3개 버전 모두 잘 동작했다)
BIND 설치에 관해 참고하면 좋은 문서: https://www.hiroom2.com/2018/05/06/ubuntu-1804-bind-en/
BIND(DNS) 설정, 운영에 관해 참고하면 좋은 문서: <-- 진짜 잘 만들어진 문서, 꼭 읽어볼 것 !! https://joungkyun.gitbook.io/annyung-3-user-guide/chapter5 - BIND 기본 설정 - 새 도메인 설정 - Slave DNS 구성 - Inverse domain 설정 - DNSSEC 설정 - GeoDNS 설정 - Domain 위임 - IDN
Install BIND pkg
##
## root 계정으로 아래 명령을 수행
##
$ apt update
$ apt install -y bind9
Configuration
파일명: /etc/bind/named.conf.options
options {
directory "/var/cache/bind";
}
참고: 원래 기본 설정이 위와 같기 때문에 수정할 내용은 없다.
파일명: /etc/bind/named.conf.local
zone "andrew.space" IN {
type master;
file "andrew.space.zone";
};
파일명: /var/cache/bind/andrew.space.zone
$TTL 86400
@ IN SOA andrew.space root.andrew.space (
2021090500
3600
900
604800
86400
)
A 10.10.9.11
@ IN NS ns1
IN NS ns2
ns1 IN A 10.10.2.3
ns1 IN A 10.10.9.3
www IN A 10.10.2.3
andrew IN A 10.10.9.71
Validation (설정 값 유효성 확인)
$ named-checkzone andrew.space /var/cache/bind/andrew.space.zone
zone andrew.space/IN: loaded serial 2021090500
OK
$ nslookup
##
## 방금 위에서 구성한 DNS 서버의 주소
##
> server 10.10.9.11
Default server: 10.10.9.11
Address: 10.10.9.11#53
##
## name zone db에 추가했던 domain name이 잘 resolution 되는 확인
##
> www.andrew.space
Server: 10.10.9.11
Address: 10.10.9.11#53
Name: www.andrew.space
Address: 10.10.2.3
>