
OpenStack의 모든 서비스를 웹 기반 GUI로 관리할 수 있게 해주는 대시보드 서비스
주요 기능
- 사용자에게 직관적인 UI 제공
- VM 생성, 네트워크 구성, 스토리지 관리 등 다양한 서비스의 시각적 관리
- 멀티테넌트 환경에서의 리소스 모니터링 및 관리
연계
- OpenStack의 대부분 서비스에 대한 GUI 제공
설치 방법
- 패키지 설치
- 패키지로 설치 후, 설정 파일만 수정하여 바로 사용 가능
- 간단하지만 커스터마이징이 어려움- 수동 설치 (수동 설치로 진행)
- 패키지 설치 보다는 복잡하지만, 커스터마이징이 가능
- 순서
- git repository에서 clone
- 관련 패키지 설치, 설정하고, 컴파일
- 아파치 웹서버 등록
cd /var/www/
git clone https://opendev.org/openstack/horizon -b unmaintained/2023.1 --depth=1
cd horizon
# 에러 발생
sudo pip3 install -c https://opendev.org/openstack/requirements/raw/branch/unmaintaned/2023.1/upper-constraints.txt .
wget https://opendev.org/openstack/requirements/raw/branch/unmaintained/2023.1/upper-constraints.txt
vi upper-constraints.txt
# 주석 처리 #
#horizon===23.1.1
pip3 install -c upper-constraints.txt .
cd openstack_dashboard/local
cp local_settings.py.example local_settings.py
vi local_settings.py
ALLOWED_HOSTS = ['10.0.0.1', '192.168.1.23']
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '10.0.0.1:11211',
},
}
OPENSTACK_HOST = "10.0.0.1:5000"
OPENSTACK_KEYSTONE_URL = "http://%s/identity/v3" % OPENSTACK_HOST
TIME_ZONE = "Asia/Seoul"
cd /var/www/horizon/
apt install gettext
./manage.py compilemessages
./manage.py collectstatic
./manage.py compress --force
apt install apache2 libapache2-mod-wsgi-py3
# fail message 무시해도 됨
./manage.py make_web_conf --wsgi
# fail message 무시해도 됨
./manage.py make_web_conf --apache > /etc/apache2/sites-available/horizon.conf
# https 사용 시 아래 코드로 진행
./manage.py make_web_conf --apache --ssl --sslkey=/path/to/ssl/key --sslcert=/path/to/ssl/cert > /etc/apache2/sites-available/horizon.conf
a2ensite horizon
service apache2 restart

cd /etc/apache2/sites-available/
a2dissite 000-default.conf
service apache2 restart
ls -al ../sites-enabled/
total 8
drwxr-xr-x 2 root root 4096 Feb 20 15:01 .
drwxr-xr-x 8 root root 4096 Feb 19 16:52 ..
lrwxrwxrwx 1 root root 31 Feb 20 14:57 horizon.conf -> ../sites-available/horizon.conf
lrwxrwxrwx 1 root root 32 Feb 19 16:43 keystone.conf -> ../sites-available/keystone.conf
lrwxrwxrwx 1 root root 37 Feb 19 18:06 placement-api.conf -> ../sites-available/placement-api.conf

cd /var/log/apache2/
# 시간순 정렬
ls -alht
total 308
-rw-r--r-- 1 root root 79862 Feb 20 15:03 placement_api_access.log
-rw-r--r-- 1 root root 151305 Feb 20 15:03 placement_api_error.log
-rw-r--r-- 1 root root 38462 Feb 20 15:03 keystone_access.log
-rw-r--r-- 1 root root 195 Feb 20 15:02 openstack_dashboard-access.log
-rw-r--r-- 1 root root 5788 Feb 20 15:02 openstack_dashboard-error.log
-rw-r----- 1 root adm 3564 Feb 20 15:01 error.log
-rw-r----- 1 root adm 1153 Feb 20 14:59 access.log
drwxr-x--- 2 root adm 4096 Feb 20 14:57 .
drwxrwxr-x 20 root syslog 4096 Feb 20 13:11 ..
-rw-r--r-- 1 root root 0 Feb 19 16:43 keystone.log
-rw-r----- 1 root adm 0 Feb 19 16:42 other_vhosts_access.log
# PermissionError 발생
tail -f openstack_dashboard-error.log
[Thu Feb 20 15:02:06.343367 2025] [wsgi:error] [pid 151227:tid 140097616774720] [remote 172.22.81.88:57037] File "<frozen importlib._bootstrap>", line 241, in _call_with_frames_removed
[Thu Feb 20 15:02:06.343371 2025] [wsgi:error] [pid 151227:tid 140097616774720] [remote 172.22.81.88:57037] File "/var/www/horizon/openstack_dashboard/settings.py", line 244, in <module>
[Thu Feb 20 15:02:06.343372 2025] [wsgi:error] [pid 151227:tid 140097616774720] [remote 172.22.81.88:57037] from local.local_settings import * # noqa: F403,H303
[Thu Feb 20 15:02:06.343373 2025] [wsgi:error] [pid 151227:tid 140097616774720] [remote 172.22.81.88:57037] File "/var/www/horizon/openstack_dashboard/local/local_settings.py", line 88, in <module>
[Thu Feb 20 15:02:06.343374 2025] [wsgi:error] [pid 151227:tid 140097616774720] [remote 172.22.81.88:57037] SECRET_KEY = secret_key.generate_or_read_from_file(
[Thu Feb 20 15:02:06.343375 2025] [wsgi:error] [pid 151227:tid 140097616774720] [remote 172.22.81.88:57037] File "/var/www/horizon/horizon/utils/secret_key.py", line 69, in generate_or_read_from_file
[Thu Feb 20 15:02:06.343376 2025] [wsgi:error] [pid 151227:tid 140097616774720] [remote 172.22.81.88:57037] key = read_from_file(key_file)
[Thu Feb 20 15:02:06.343377 2025] [wsgi:error] [pid 151227:tid 140097616774720] [remote 172.22.81.88:57037] File "/var/www/horizon/horizon/utils/secret_key.py", line 51, in read_from_file
[Thu Feb 20 15:02:06.343378 2025] [wsgi:error] [pid 151227:tid 140097616774720] [remote 172.22.81.88:57037] with open(key_file, 'r') as f:
[Thu Feb 20 15:02:06.343382 2025] [wsgi:error] [pid 151227:tid 140097616774720] [remote 172.22.81.88:57037] PermissionError: [Errno 13] Permission denied: '/var/www/horizon/openstack_dashboard/local/.secret_key_store'
cd /var/www/
ls -altt
total 16
drwxr-xr-x 15 root root 4096 Feb 20 14:53 horizon
drwxr-xr-x 4 root root 4096 Feb 20 14:42 .
drwxr-xr-x 2 root root 4096 Feb 19 16:42 html
drwxr-xr-x 14 root root 4096 Feb 19 16:42 ..
chown www-data:www-data horizon/ -R

인증 메뉴 동작 X
identity 경로의 충돌
- keystone도 identity 경로를 쓰고, horizon도 사용함
- 포트 번호가 다르지만 Apache에서 충돌이 발생
해결 방법
- horizon의 루트 경로를 / 에서 /horizon 으로 변경
- horizon의 identity → /horizon/identity로 수정됨
cd /var/log/apache2/
ls -alht
total 5.3M
-rw-r--r-- 1 root root 88K Feb 20 15:16 placement_api_access.log
-rw-r--r-- 1 root root 164K Feb 20 15:16 placement_api_error.log
-rw-r--r-- 1 root root 61K Feb 20 15:15 keystone_access.log
-rw-r--r-- 1 root root 26K Feb 20 15:15 openstack_dashboard-access.log
-rw-r--r-- 1 root root 4.9M Feb 20 15:15 openstack_dashboard-error.log
-rw-r----- 1 root adm 3.5K Feb 20 15:01 error.log
-rw-r----- 1 root adm 1.2K Feb 20 14:59 access.log
drwxr-x--- 2 root adm 4.0K Feb 20 14:57 .
drwxrwxr-x 20 root syslog 4.0K Feb 20 13:11 ..
-rw-r--r-- 1 root root 0 Feb 19 16:43 keystone.log
-rw-r----- 1 root adm 0 Feb 19 16:42 other_vhosts_access.log
# 로그 띄워두고 에러 화면 새로고침해서 확인
tail -f openstack-dashboard-error.log
[Thu Feb 20 15:19:01.013964 2025] [wsgi:error] [--------------------] [client --------------------] Daemon process called 'keystone-public' cannot be accessed by this WSGI application: /usr/bin/keystone-wsgi-public, referer: http://192.168.1.23/admin/flavors/
cd /var/www/horizon/
cd openstack_dashboard/local
vi local_settings.py
DEBUG = False
WEBROOT = "/horizon/"
cd /etc/apache2/sites-available/
vi horizon.conf
RewriteEngine on
RewriteCond %{REQUEST_URI} ^/$
RewriteRule ^/$ /horizon/ [R=301,L]
WSGIScriptAlias /horizon /var/www/horizon/openstack_dashboard/horizon_wsgi.py
<Location "/horizon">
Require all granted
</Location>
Alias /horizon/static /var/www/horizon/static
<Location "/horizon/static">
SetHandler None
</Location>
a2enmod rewrite
systemctl restart apache2
