본문 바로가기

Ryu's Tech

오픈스택 오카타 자동 설치 스크립트 (bash)

Table of Contents


개요

먼저 이 글을 쓰게 된 계기는 openstack ocata (오픈스택 오카타) 버전으로 넘어오면서 기본적인 서비스 설치와 동작 방법(기본설정~네트워크생성)이 크게 변화가 없어졌고 기존 설치 과정을 스크립트화 할 수 있다면 devstack을 설치하는 것보다 더 좋을 것 같다는 생각이 들었습니다.

저만을 위한 스크립트가 아니라 다른 분들도 활용할 수 있도록 config 파일 형태로 필요한 값들을 전달해서 설치할 수 있도록 짜두었고, 별도 컴퓨트 서버가 없는 올인원(AIO) 형태의 설치와 컴퓨트 노드가 늘어나도 좀 더 유연하게 설치가 될 수 있도록 만들어 보았습니다.

인터넷이 연결된 상태에서 config 파일만 본인에게 맞게 수정한다면 간단하게 설치가 가능하실겁니다.

데모

아래 github를 통해 올인원 형태로 설치되는 풀 영상으로 스레드리퍼 CPU사용자의 이유로 kernel update만 적용된 상태입니다.

환경 설명 - VMware 환경 / Centos 7 64x 1708 버전 / CPU 16 / RAM 32G / 가상화 옵션 켬

총 30분정도 소요되네요.

설치방법

중간에 설치 방법을 넣으면 너무 정신없을것 같아 설치 방법을 먼저 정리해두겠습니다.

먼저 github에도 간단한 설명이 나와있습니다.

openstack-ocata-install-script GITHUB 주소

yum install -y -q git
git clone https://github.com/ryusstory/openstack-ocata-install-script.git
cd openstack-ocata-install-script/
chmod +x *.sh

위와 같이 설정한 뒤 config.sh 파일을 수정한 뒤 ./00-pre.sh 로 스크립트를 실행 시키면 됩니다.  

이와 관련해서는 아래에 설명해두겠습니다. 바로 아래 config.sh 파일만 보셔도 됩니다.

자세한 내용은 아래 설치 스크립트 설명과 스크립트 일부 설명을 보시면 도움이 될 수도 있습니다.

설치 스크립트 설명

스크립트 내용은 오픈스택 공식 사이트 가이드 OpenStack Installation Tutorial for Red Hat Enterprise Linux and CentOS에 해당되는 내용으로 아래 스크립트 설명은 해당 절차에서 나오지 않거나 별도 수정된 부분만 설명하겠습니다.

config.sh

패스워드 

기본 컨피그 설정으로 오픈스택 공식가이드의 패스워드 설정에 관련 된 부분을 별도로 지정할 수 있도록 하였습니다.

그래서 스크립트 기본으로 설치시 웹 대시보드 접근 패스워드도 admin에 ADMIN_PASS 로 접속하시면 됩니다.

아래와 같이 설정되어 있고 우측 값을 바꾸시면 원하시는 패스워드로 설정됩니다. 실제 스크립트에는 해당 값으로 치환되어 들어가게 됩니다.

DBPASS=DBPASS
ADMIN_PASS=ADMIN_PASS
RABBIT_PASS=RABBIT_PASS

METADATA_SECRET=METADATA_SECRET
KEYSTONE_DBPASS=KEYSTONE_DBPASS

GLANCE_DBPASS=GLANCE_DBPASS
GLANCE_PASS=GLANCE_PASS

NOVA_DBPASS=NOVA_DBPASS
NOVA_PASS=NOVA_PASS
PLACEMENT_PASS=PLACEMENT_PASS

NEUTRON_DBPASS=NEUTRON_DBPASS
NEUTRON_PASS=NEUTRON_PASS

DASH_DBPASS=DASH_DBPASS

HEAT_PASS=HEAT_PASS
HEAT_DBPASS=HEAT_DBPASS
HEAT_DOMAIN_PASS=HEAT_DOMAIN_PASS

노드 설정

중요한 노드 수와 일부 옵션에 대한 부분을 설명드리면 아래와 같이 배열 형태로 차례로 입력해주셔야 합니다.

[0]에는 컨트롤러 노드 혹은 올인원 노드 / [1] 부터 컴퓨트 노드에 대한 정보를 넣으면 됩니다.

QUIETYUM=1
INSTALL_HEAT=1
INIT_OPENSTACK=1
COMPUTENODE=0

HOST_ip[0]=192.168.0.11
HOST_name[0]=controller
HOST_pass[0]=qwe123

HOST_ip[1]=192.168.0.21
HOST_name[1]=compute1
HOST_pass[1]=qwe123

COMPUTENODE

핵심 설정 부분으로 0 일시 올인원, 1~x 는 컴퓨트 노드 수입니다.

COMPUTENODE 변수가 0 일 때는 for문에 의해 아래 HOST_ip[1] 등이 무시되므로 삭제할 필요는 없습니다.

QUIETYUM

yum 설치 부분에 QUIET 옵션으로, 1로 설정하면 -quiet 옵션이 들어가 yum output이 최소화 됩니다.

모든 yum 설치 부분이 아래와 같이 처리되어 있어 -q 옵션을 통해 설치할 수 있습니다.

설치 후 잘못된 부분을 찾을 경우 yum 로그가 너무 많아 어디서부터 잘못됐는지 찾기가 어려워 옵션을 넣어뒀습니다.

PKGS='expect'
if [ $QUIETYUM -eq 1 ]; then yum install -q -y $PKGS
else yum install -y $PKGS; fi

INSTALL_HEAT / INIT_OPENSTACK

묶어서 설명드리면 적혀있는 대로 INSTALL_HEAT는 히트 오케스트레이션 서비스 설치 유무

INIT_OPENSTACK은 최초 설정 이후 공식 가이드의 네트워크 생성, 서브넷 생성, flavor 생성, cirros 이미지 다운로드, 키 생성, 보안그룹 생성, 인스턴스 생성 에 대한 부분을 스크립트화 해놨습니다. 각자의 환경에 맞게 하셔야 되기 때문에 참고 후 직접 적용하시는 걸 추천드립니다.

적용 방식은 아래 00-pre.sh에서 설명드리겠습니다.

00-pre.sh

처음에는 환경 설정만 잡아주는 쉘스크립트였는데 지금은 00-pre.sh 만 실행시키면 전체 설치가 진행됩니다.

1.sh && 2.sh && 3.sh && 4.sh 형태로 설치도 해봤는데 길이가 너무 길어서 그런건지 중간에 끊기게 되어서 이런방법을 사용했습니다.


전체적인 과정을 설명드리면 아래와 같습니다.

인터넷 체크 > 호스트네임 설정 > SSH 키 생성 > SSH 키 복사 > 스크립트 파일 차례로 실행

이와 같은 방식을 사용하는 이유는 머신이 최초 부팅시 localhost 형태로 접속되고 여기서 설정을 진행할 경우 rabbitmq 설치과정에서 호스트네임 미스매치로 전체 부분이 진행이 잘못되게 됩니다. 

그래서 호스트네임적용을 위해 로컬머신까지도 ssh로 접속해서 실행하게 됩니다. 그렇지 않으면 접속을 끊거나 중간에 손이 가는 부분이 발생하기 때문에 한번에 모든 절차를 처리하려고 이렇게 작성했습니다.

아래 부분은 위의 INSTALL_HEAT와 INIT_OPENSTACK에 대해 처리하는 방식으로 git을 통해 받아진 폴더의 파일 리스트를 배열로 저장하고 설치될 노드에 config 파일을 복사한 뒤 차례로 실행되도록 했습니다.


if [ $INSTALL_HEAT -eq 1 ]; then shfile=($(ls | grep -e "[0-9][0-9][-].*[.]sh" | grep -v "00-pre.sh" | sed 's/:.*//'))
else shfile=($(ls | grep -e "[0-9][0-9][-].*[.]sh" | grep -v "00-pre.sh" | grep -v "heat" | sed 's/:.*//'))
fi
if [ $INIT_OPENSTACK -eq 0 ]; then unset "shfile[${#shfile[@]}-1]"; fi

# copy config file for script
for ((i = 0; i <= $COMPUTENODE; i++))
do
scp ./config.sh ${HOST_name[$i]}:
done

# run scripts
echo ${shfile[*]}
for i in "${shfile[@]}"
do
ssh ${HOST_name[0]} 'bash -s' < $i
done


10-basic.sh

오픈스택 가이드 environement에 해당하는 설치 내용입니다.

하지만 아래 부분이 좀 다르게 추가되어 있습니다. 이와 같이 하는 이유는 my.cnf 파일의 [mysqld] 파트에 max_connection=4096을 적용하더라도 max limit 이 적용되어 있어 max_connection의 변화가 없습니다.

이를 처리하기 위해 최대치를 풀어주기 위한 스크립트입니다. 이렇게 하지 않으면 최대치에 맞는 숫자를 입력하거나 매번 부팅 시 적용해 주어야 하는데 DB_PASS를 입력해야하기 때문에 어려움이 있습니다.

해당 내용은 이곳 링크를 참고하시면 확인하실 수 있습니다.

sed -i "/\[Service\]/a LimitNOFILE=4096" /usr/lib/systemd/system/mariadb.service
systemctl daemon-reload

그리고 차후 뒷부분에도 모두 적용되겠지만 아래와 같이 backup파일을 만들고 빈줄과 주석을 전부 삭제하여 스크립팅에 편하도록 하였습니다. 차후 더 빠른 설치를 원하시는 분은 완벽한 conf 파일만 복사해서 설치를 진행하시면 훨씬 더 빠르고 정적으로 설치를 완료하실 수 있습니다.

cp /etc/keystone/keystone.conf /etc/keystone/backup.keystone.conf
sed -i '/^#/d' /etc/keystone/keystone.conf
sed -i '/^$/d' /etc/keystone/keystone.conf

20-keystone.sh

오픈스택 가이드 Identity에 해당하는 설치 내용입니다.

keystone에 대한 부분으로 특별한 부분 없습니다.

30-glance.sh

오픈스택 가이드 Image에 해당하는 설치 내용입니다.

glance에 대한 부분으로 glance 서비스를 확인하는 cirros를 받아서 등록하는 절차는 주석처리해뒀고 이후 99-init.sh 에서 적용되게 됩니다.

40-nova.sh

오픈스택 가이드 Compute에 해당하는 설치 내용입니다.

libvirt에 대한 설정 중 기존 설치 가이드는 qemu 이지만 kvm으로 변경해뒀습니다 필요시 수정해서 사용하시길 바랍니다.

sed -i '/\[libvirt\]/a virt_type = kvm' /etc/nova/nova.conf

공식 가이드의 설치 절차에는 없지만 편의상 ratio를 적용해 뒀습니다. 관련 문서는 이곳을 참조하시길 바랍니다.

cpu와 ram의 경우 눈에 보이는 수치이지만 disk는 눈에 보이지 않는 수치일 수도 있습니다.

disk ratio가 1.0(기본) 일 경우 100GB의 공간이 있는 컴퓨트 노드에 11GB의 인스턴스 9개를 배포시 99GB이지만 실제로 머신에서 차지하고 있는 용량은 훨씬 작을 수 있습니다. 

공간은 50GB 이상이 보이고 있어도 할당되어 있는 공간은 이미 99GB 이기 때문에 이 이상 인스턴스를 배포하려면 용량은 남은 것처럼 보이나 no valid host 에러로 인스턴스가 배포되지 않습니다.

[DEFAULT]
cpu_allocation_ratio = 16.0
disk_allocation_ratio = 2.0
ram_allocation_ratio = 2.0

컨트롤러에 설치하는 절차 중 아랫쪽 패키징 버그 때문에 들어가는 코드는 한달이 지났는데 그대로 있네요. 해당 부분도 포함되어 있습니다.

echo "
<Directory /usr/bin>
<IfVersion >= 2.4>
Require all granted
</IfVersion>
<IfVersion < 2.4>
Order allow,deny
Allow from all
</IfVersion>
</Directory>
" >> /etc/httpd/conf.d/00-nova-placement-api.conf
systemctl restart httpd

VNC 부분 관련해서 오픈스택 가이드는 hostname으로 설정되어 있지만 본 스크립트는 이를 IP로 바꿔 놨습니다.

이와 같이 적용한 이유는가상머신에 올려놓고 접속해서 사용할 시에 hostname 정보가 없어 콘솔창이 404로 뜨게 됩니다. 이를 해결하기 위해 IP로 변경했습니다.

sed -i "/\[vnc\]/a novncproxy_base_url = http://${HOST_ip[0]}:6080/vnc_auto.html" /etc/nova/nova.conf

50-neutron.sh

오픈스택 가이드 Networking에 해당하는 설치 내용입니다.

뉴트론 설치 부분으로 네트워크 옵션 2로만 작성하였습니다. 옵션을 나누는건 어렵지 않으나 지금 당장 필요성이 없어서 작성하지 않았습니다.

네트워크 옵션 2만 제공되는 점 꼭 참고 바랍니다.

중간의 네트워크 옵션에서 프로바이더 인터페이스를 추가해야 하는 부분이 있습니다.

[linux_bridge]
physical_interface_mappings = provider:PROVIDER_INTERFACE_NAME

해당 컨피그는 앞의 노드 IP가 설정된 인터페이스를 찾아서 넣게 해놨습니다.

...= provider:$(ip a | grep -B 2 ${HOST_ip[0]} | grep UP | awk -F: {'print $2'} | tr -d ' ')"...

55-heat.sh

오픈스택 가이드 Orchestration에 해당하는 설치 내용입니다.

히트 서비스 설치로 특별한 차이는 없으나 최초 서비스 설치 시 heat.conf에 [keystone_authtoken] 섹션이 없습니다.

그래서 해당 부분은 치환이 아닌 echo로 처리했습니다.

echo "[keystone_authtoken]
auth_uri = http://${HOST_name[0]}:5000
auth_url = http://${HOST_name[0]}:35357
memcached_servers = ${HOST_name[0]}:11211
auth_type = password
project_domain_name = default
user_domain_name = default
project_name = service
username = heat
password = $HEAT_PASS" >> /etc/heat/heat.conf

그리고 중간에 절차를 넣은 이유는 설치 시 dashboard 서비스를 재시작 해야되기 때문에 편의상 중간에 넣어뒀습니다.

60-horizon.sh

오픈스택 가이드 Dashboard에 해당하는 설치 내용입니다.

드디어 마지막 서비스네요. 대시보드입니다.

아래 접속가능 호스트만 공식 가이드의 코멘트처럼 *로 처리했습니다.

sed -i "/ALLOWED_HOSTS/c\ALLOWED_HOSTS = ['*']" /etc/openstack-dashboard/local_settings

이 부분이 테스트 중 문제가 되서 적용을 했었는데 아래 버그가 있습니다.

mod_wsgi requires WSGIApplicationGroup %{GLOBAL} or it will hang

echo "WSGIApplicationGroup %{GLOBAL}" >> /etc/httpd/conf.d/openstack-dashboard.conf

99-init.sh

오픈스택 가이드 Launch an instance에 해당하는 설치 내용입니다.

그냥 일자로 쭉 실행하게 됩니다. 절차를 설명드리면 좀 길지만 아래와 같습니다.

외부 네트워크 생성 > 외부 네트워크의 서브넷 생성 > 내부 네트워크 생성 > 내부 네트워크의 서브넷 생성 > 라우터 생성 > 

라우터 설정 및 게이트웨이 설정 > flavor 생성 > cirros 이미지 다운로드 > 오픈스택 내 cirros 이미지 등록 > 

보안그룹 생성 > 보안룰 추가 > 접속용 keypair 생성 > 인스턴스(server) 생성 > 외부 네트워크의 floating IP 연동


오픈스택 공식가이드에는 아래 형태로 설명이 나와있는데 해당 부분이 문제가 좀 있었습니다. 기억은 잘 안나는데 "default" 부분의 인식 문제였었습니다.

openstack security group rule create --proto icmp default
openstack security group rule create --proto tcp --dst-port 22 default

그래서 그냥 새로 생성해서 security group의 ID를 직접 받아넣는 형태로 바꿔놨습니다.

openstack security group create initrule
openstack security group rule create \
--protocol icmp $(openstack security group show initrule | grep -e " id " | awk '{print $4}')
openstack security group rule create --protocol tcp \
--dst-port 22 $(openstack security group show initrule | grep -e " id " | awk '{print $4}')




추가내용. 스크립트 일부 설명

스크립트의 경우 간소화가 되다 보니 해석에 어려울 수 있어 몇몇 스크립트의 핵심 부분을 설명을 드리겠습니다.

배열 in bash script

다수의 컴퓨트 노드가 늘어나는 부분에 대한 설치 스크립트를 작성하기 위해서 노드들을 배열을 통해 저장하도록 했습니다.

아래의 형태로 config.sh 파일에 저장하고 사용시에는 ${HOST_name[$i]} 형태로 사용해 for문을 통하는 등의 묶음 처리에 유연하게 사용할 수 있도록 작성했습니다.

HOST_ip[0]=192.168.0.11
HOST_name[0]=controller
HOST_pass[0]=qwe123

HOST_ip[1]=192.168.0.21
HOST_name[1]=compute1
HOST_pass[1]=qwe123

HOST_ip[2]=192.168.0.22
HOST_name[2]=compute2
HOST_pass[2]=qwe123

keygen & expect

ssh-keygen을 통해 키를 생성하고 접속할 곳에 해당 키를 복사 해 ssh 접속시 패스워드를 묻지 않고 바로 접속해서 쉘 프롬프트를 뜨도록 하는 것이 목적입니다.

expect는 ssh 최초 접속시에 두가지 경우가 발생하는데 최초 접속시 키 등록 및 키가 맞지 않으면 패스워드를 물어보게 됩니다.


[root@controller ~]# ssh 192.168.0.21
The authenticity of host '192.168.0.21 (192.168.0.21)' can't be established.
ECDSA key fingerprint is SHA256:hWnim5AXu4D50BYf1JjrFsdqvbAlJtfZors71nNwlYc.
ECDSA key fingerprint is MD5:26:e8:df:04:36:e4:2a:01:63:d3:4b:40:4e:ec:0b:6e.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.0.21' (ECDSA) to the list of known hosts.
root@192.168.0.21's password:
Last login: Sat Dec 16 01:41:50 2017
[root@compute1 ~]#

이 두 과정을 처리하기 위해 expect 를 사용해서 처리하였습니다. 이와 같은 방법을 사용하면 ssh 키 복사에 대한 최초 시도시 스크립트화가 가능합니다.

ssh-keygen -t rsa -N "" -f ~/.ssh/id_rsa

for ((i = 0; i <= $COMPUTENODE; i++))
do
/usr/bin/expect <<EOE
set prompt "#"
spawn bash -c "ssh-copy-id -f ${HOST_name[$i]}"
expect {
"yes/no" { send "yes\r"; exp_continue}
-nocase "password" {send "${HOST_pass[$i]}\r"; exp_continue }
$prompt
}
EOE
done

ssh를 통한 스크립트 원격 실행

아래 코드를 보면 compute 노드가 1개 이상일 경우 nova.sh 스크립트 파일에 config.sh내용을 복사하고 그 아래에 필요한 스크립트를 덧붙였습니다.

그리고 중간의 compute_node의 IP가 들어갈 부분을 NODE_IP로 설정해두고 스크립트 파일을 원격으로 실행하기 전 해당 for index의 값을 NODE_IP와 치환하여 각 노드에 맞게 스크립트를 원격 실행합니다.

if [ $COMPUTENODE -eq 0 ]
then
생략...(AIO 설치시 스크립트)

elif [ $COMPUTENODE -ge 1 ]
then
cat config.sh > nova.sh
echo 'NODE_IP=' >> nova.sh
cat << "EOZ" >> nova.sh
생략...(컨피그 추가되는 부분)
sed -i "/\[DEFAULT\]/a my_ip = ${NODE_IP}\nenabled_apis = osapi_compute,metadata\n...생략
생략...(컨피그 추가되는 부분)
EOZ
for ((i = 1; i <= $COMPUTENODE; i++))
do
sed -i "/^NODE_IP/c\NODE_IP=\${HOST_ip[$i]}" nova.sh
ssh ${HOST_name[$i]} 'bash -s' < nova.sh
done
fi