新手轻喷,不定期更新… …
这里是用docker搭建openstack实验环境的手工记录,是一步步实际操作而来,因此不会用到script来进行自动化处理。等我实际搭建成功后会写一个自动化的搭建脚本。
目录
一,需求及基础环境
- 需求:博主现正进行openstack相关的开发,刚开始接触这个项目,但苦于其规模庞大,同时其部署非常麻烦且易出错,对新手极其不友好。博主现在只使用mirantis在虚拟机上搭建成功过一次,部署一次非常麻烦且耗时很长,因此想利用docker的便捷性快速搭建openstack的实验环境。当然博主考察过kolla项目,它就是使用docker来部署openstack的,但限于网络问题,如果不将其docker的repo的地址更改到国内一些镜像源,则实际上是无法使用的,但这个项目也非常庞大,对新手而言还是很不友好,还不如自己动手,丰衣足食 >_<
- 基础环境:
$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 16.04.6 LTS
Release: 16.04
Codename: xenial
$ uname -a
Linux docker 4.4.0-157-generic #185-Ubuntu SMP Tue Jul 23 09:17:01 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
$ docker --version
Docker version 18.09.7, build 2d0083d
这里由于博主的工作笔记本用的是windows,但是WSL毕竟不是linux,而且windows对docker的支持也面临许多权限的限定,特别是关于网络设备这类比较底层的问题,WSL是没有权限操作的。综合各方面因素考虑博主是使用虚拟机作为主机的,可以选择ubuntu14/16版本的,至于debian,redhat,suse等也可以,但博主没有试过,其可以调整内存、磁盘、cpu等参数,比较方便。因为openstack的节点多的时候对计算机资源的要求是很大的,最好能选用大一些的内存和磁盘空间。具体多少等博主实际测过后再说。
二,搭建过程
1,搭建局域网内的apt源
因为在openstack的搭建过程中,非常容易出问题,这时网速就成为最令人头疼的问题,如果能在本地的局域网内搭建一个apt源,则可以大大减轻由网络异常带来的问题,甚至可以说已成功了一半。

上图是使用container搭建局域网内apt源的网络拓扑,使用的网络是docker的默认网桥,因为该网桥可以连通外部网络,同时每个container默认都连接这个网桥,所以非常合适。
(1) 安装http server
http server可以有很多选择,我这里就简单地使用Apache。
## 进入container
$ docker run -it ubuntu:16.04.3 /bin/bash
## 使用这个container作为apt server
$ apt update
$ apt install -y apache2
## 启动apache
$ service apache2 start
## 检查apache是否正常启动
$ service apache2 status
为了检查apt server是否正常启动http的服务,可以在docker所在的主机或任何能连上局域网(172.17.0.2/16)的主机向它发送http的请求
# 在apt server的container中
$ cd /var/www/html
$ echo "apache run successfully!" > test.txt
# 然后在另一个在该局域网内的主机上
$ curl -g -i -X GET http://172.17.0.2/test.txt
HTTP/1.1 200 OK
Date: Thu, 26 Sep 2019 01:34:40 GMT
Server: Apache/2.4.18 (Ubuntu)
Last-Modified: Thu, 26 Sep 2019 01:21:31 GMT
ETag: "1a-5936a96ef8426"
Accept-Ranges: bytes
Content-Length: 26
Content-Type: text/plain
apache run successfully!
## 显示成功,说明http服务已开启
(2) 搭建apt源
参考资料:
How to create a local APT repository?: 这是stackflow中的问题,里面的讨论很详细,由apt本地源拓展到局域网,以及认证问题。
## 准备好工具
$ sudo apt-get install dpkg-dev
## 准备好apt库的位置,因为使用apache2做为http服务,为了简单起见,直接使用其默认的路径
$ cd /var/www/html
$ ls
index.html
## index.html是apache的主页面,这个路径就是apache的默认主路径
## 在这个路径下设置离线库
$ mkdir -p debs/amd64 && cd debs/amd64
## 通过外网下载需要的离线包,同时保证依赖的库也能一起下载下来
$ apt-cache depends <packagename> -i --recurse | awk '/^[a-z]/ {print $0}' | xargs apt-get download
## 当下载完成后需要扫描生成包的信息文件
$ cd .. ## -> debs
$ dpkg-scanpackages amd64 /dev/null | gzip -9c > amd64/Packages.gz
(3) 添加apt源
当apt server搭建好之后,需要认局域网内的其它主机能够使用这个源,因为本文主要服务于openstack基于docker的搭建,因此让所有其它的container都使用这个apt源
## 进入另外一个新的container中,首先确定其能连接到apt server的http服务,
## 这一步参考[(1)安装http server]的验证操作
$ cd /etc/apt/
$ mv sources.list sources.list.backup
$ echo "deb http://172.17.0.2/debs amd64/" > sources.list
## 更新及下载
## 注意,由于这里为了简便没有建权的步骤,
## 关于建权的部分,可以参考[(2) 搭建apt源]的资料
$ sudo apt-get --allow-unauthenticated update
Ign:1 http://172.17.0.2/debs amd64/ InRelease
......
Fetched 49.8 kB in 1s (30.8 kB/s)
Reading package lists... Done
$ sudo apt-get --allow-unauthenticated install <packagename>
(4) 验证apt源 --> 实例
按照上面两步可以在局域网内搭建好一个apt源,现在以安装ping为例来验证这个局域网内的apt源是否正常工作
## 进入apt server中,准备好ping的安装包及依赖
$ apt-cache depends iputils-ping -i --recurse | awk '/^[a-z]/ {print $0}' | xargs apt-get download
$ cd /var/www/html/debs
$ dpkg-scanpackages amd64/ /dev/null | gzip -9c > amd64/Packages.gz
## 任意进入一个已经添加了apt server源的container中
$ sudo apt-get --allow-unauthenticated update
$ sudo apt-get --allow-unauthenticated install iputils-ping
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following NEW packages will be installed:
iputils-ping
0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 0 B/52.7 kB of archives.
After this operation, 164 kB of additional disk space will be used.
WARNING: The following packages cannot be authenticated!
iputils-ping
Authentication warning overridden.
debconf: delaying package configuration, since apt-utils is not installed
Selecting previously unselected package iputils-ping.
(Reading database ... 27948 files and directories currently installed.)
Preparing to unpack .../iputils-ping_3%3a20121221-5ubuntu2_amd64.deb ...
Unpacking iputils-ping (3:20121221-5ubuntu2) ...
Setting up iputils-ping (3:20121221-5ubuntu2) ...
Setcap is not installed, falling back to setuid
$ ping -c 1 172.17.0.2
PING 172.17.0.2 (172.17.0.2) 56(84) bytes of data.
64 bytes from 172.17.0.2: icmp_seq=1 ttl=64 time=0.091 ms
--- 172.17.0.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.091/0.091/0.091/0.000 ms
可以看见验证成功!
2,本地源码编绎deb包
在container环境下部署openstack有时会遇到从apt源中得到的包无法正常使用或干脆无法使用的情况,这时就只能下载适配的源码,手动编绎安装了。但这个过程是枯燥的,而且当部署量较大时也非常麻烦,不便于管理,因此需要将源码本地打包。
使用的工具: checkinstall,这个工具在官方的apt源中有,可以直接使用apt install得到它
参考资料: Linux 的源码安装工具 CheckInstall: 这个有对checkinstall的使用的简单介绍
下面以chrony源码为例
$ cd chrony-3.5
## 这里是各种编绎选项,为了后续使用方便,把安装路径都写成"/usr",因为默认路径一般是"/usr/local",这样还要去修改环境变量。
$ ./configure --prefix=/usr ## 这里是各种编绎选项
$ make
## 打包
$ checkinstall
checkinstall 1.6.2, Copyright 2009 Felipe Eduardo Sanchez Diaz Duran
This software is released under the GNU GPL.
The package documentation directory ./doc-pak does not exist.
Should I create a default set of package docs? [y]: y
...
## 在打包时会有一些交互性的问题,按照提示写入即可
$ ls chrony_3.5-1_amd64.deb
## 查看编绎成功的deb包
$ dpkg -I chrony_3.5-1_amd64.deb
new debian package, version 2.0.
size 256614 bytes: control archive=330 bytes.
0 bytes, 0 lines conffiles
234 bytes, 12 lines control
Package: chrony
Priority: extra
Section: checkinstall
Installed-Size: 1084
Maintainer: root@sola
Architecture: amd64
Version: 3.5-1
Provides: chrony
Description: chrony-3.5
compiled by eouylei, used for deployment in docker.
3,建立openstack的局域网apt源
有了前面两步的基础,现在可以根据openstack官网的要求,将其需要的所以依赖都下载下来构建一个局域网内的apt源,同时还可以将一些不适应container的包替换成合适的包。
(1) 更新相应包的脚本
为了方便安装,以下是用于从远程APT源下载相应包(包括其依赖的包)到本地apache2下面,并建立本地APT源的脚本
update_local_apt_repo.sh
方法: update_local_apt_repo.sh [packages]
例: update_local_apt_repo.sh vim apache2 iproute2 iputils-ping
## openstack_repo_dir 与 openstack_repo 为两个环境变量,其表示httpd server的根路径与源的名字
## 例如:apt客户端指定source.list为 "deb http://172.17.0.2/debs openstack/"
## 而apt server指定的根路径为"/var/www/html"
## 则 openstack_repo_dir=/var/www/html/debs
## openstack_repo=openstack
repo_dir=$openstack_repo_dir
repo=$openstack_repo
err_log="$HOME/update_local_apt_repo_err.log"
packages=$*
existed_packages_str=""
install_failed_packages=""
install_existed_packages=""
function init_err_log() {
[ -f $err_log ] || touch $err_log
printf "
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
start date: %s
script wants to apt download debs as followed:
<%s>
start download... ... ...
" "$(date)" "$packages" | tee -a $err_log
}
function finish_err_log() {
printf "
finish ... ... ...
finish date: %s
--> all the packages are:
<$packages>
--> already existed packages are:
<$install_existed_packages>
--> failed packages are:
<$install_failed_packages>
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
" "$(date)" | tee -a $err_log
}
function show_err_and_exit() {
echo "Error: $1" | tee -a $err_log
exit 1
}
function generate_existed_package_array() {
echo "-----> scanning existed packages ... ... ..." | tee -a $err_log
cd $repo_dir/$repo
existed_packages_str=$(gunzip -9c Packages.gz | egrep "^Package:" | \
cut -d ' ' -f 2)
}
function assert_package_not_existed() {
local package="$1"
local result=""
result=$(echo "$existed_packages_str" | \
while read item;
do
if [ "$item" = "$package" ]; then
echo "existed"
return 0
fi
done
)
[ "$result" = "existed" ] && return 1 || return 0
}
init_err_log
[ -z "$repo_dir" -o -z "$repo" ] && \
show_err_and_exit "The envir argv is not exist!"
[ -d $repo_dir ] || \
show_err_and_exit "the dir of repo <$repo_dir> is not exist!"
[ -d $repo_dir/$repo ] || \
show_err_and_exit "repo <$repo_dir: $repo> is not exist!"
generate_existed_package_array
cd $repo_dir/$repo
for package in $@;
do
printf "\n--> start to download apt debs <$package>\n" | \
tee -a $err_log
assert_package_not_existed "$package"
if [ $? != 0 ]; then
printf "the package <$package> is existed, jump it\n" | \
tee -a $err_log
install_existed_packages="$install_existed_packages $package"
continue;
fi
printf " download package <$package>\n" | tee -a $err_log
apt-cache depends "$package" -i --recurse | \
awk '/^[a-z]/ {print $0}' | \
xargs apt-get download
if [ $? != 0 ]; then
echo "**** Exception: apt download <$package> failed" | \
tee -a $err_log;
install_failed_packages="$install_failed_packages $package"
fi
done
printf "\n***********\n" | tee -a $err_log
cd ..
dpkg-scanpackages $repo /dev/null | \
gzip -9c > \
$repo/Packages.gz 2>&1 | tee -a $err_log
finish_err_log
(2) 需要的软件包
参考资料:
openstack Environment:下面的包就是根据这部分安装文档来的,如果要安装其它版本也是一样的做法
| 项目 | 包 | 备注 |
|---|---|---|
| Security | - | - |
| Host networking | - | - |
| Network Time Protocol (NTP) | chrony | 如果发现使用有问题(参考下面的内容),需要按照上述方法手工制作deb包 |
| OpenStack package | python-openstackclient | 请参考该文档,根据docker image选择,博主这里用的是ubuntu 16.04,请按照下面注释[python-openstack]的方式下载 |
| SQL database | mariadb-server python-pymysql | - |
| Message queue | rabbitmq-server | - |
| Memcached | memcached python-memcache | - |
| Etcd | etcd | - |
- python-openstackclient
这个软件包需要加载以下apt库
$ apt install software-properties-common
$ add-apt-repository cloud-archive:queens
这里博主根据自己的docker images为ubuntu16.04而选择了Queens版本
| 项目 | 包 | 备注 |
|---|---|---|
| keystone | keystone apache2 libapache2-mod-wsgi | - |
| glance | glance | - |
| nova | nova-api nova-conductor nova-consoleauth nova-novncproxy nova-scheduler nova-placement-api nova-compute | 其中nova-compute是为compute节点准备的 |
| neutron for controller | neutron-server neutron-plugin-ml2 neutron-linuxbridge-agent neutron-dhcp-agent neutron-metadata-agent | Networking Option 1: Provider networks |
| … | neutron-server neutron-plugin-ml2 neutron-linuxbridge-agent neutron-l3-agent neutron-dhcp-agent neutron-metadata-agent | Networking Option 2: Self-service networks |
| neutron for compute | neutron-linuxbridge-agent | - |
| horizon | openstack-dashboard | - |
| cinder for storage | lvm2 thin-provisioning-tools | - |
| cinder for controller | cinder-api cinder-scheduler | - |
| cinder for backup | cinder-backup | - |
…
三,遇到的问题
* pip install 时locale.Error: unsupported locale setting
参考locale.Error: unsupported locale setting 的解决方案
$ locale ## 查看当前语言设置
$ locale -a ## 查看当前系统所有可用语言
## 根据比对发现有某种语言缺失,便是原因所在
## 解决方法:
* 下载该语言包 'sudo apt install language-pack-xxxxx'
* 直接更改当前语言设置 'export LC_ALL=C'
* 安装keystone的依赖 --> Modules/constants.h
问题描述:在安装keystone的依赖时,触发了以下错误:
In file included from Modules/LDAPObject.c:8:0:
Modules/constants.h:7:18: fatal error: lber.h: Aucun fichier ou dossier de ce type compilation terminated.
error: command ‘x86_64-linux-gnu-gcc’ failed with exit status 1
解决方法:
## You need to have the development files (headers) in order to compile the Python module.
$ sudo apt-get install libsasl2-dev python-dev libldap2-dev libssl-dev
参考资料:
pip install -r requirements.txt fails on linux #8849
* container里运行chronyd或ntpd时failed, <adjtimex() failed>
先更新到最新版本,旧的版本似乎不支持在container中运行,因为涉及硬件的时间处理。
## remove existed chrony
$ apt purge chrony
$ wget https://launchpad.net/ubuntu/+archive/primary/+sourcefiles/chrony/3.5-2ubuntu2/chrony_3.5.orig.tar.gz
## make and install chrony
$ tar xzvf chrony_3.5.orig.tar.gz
$ cd chrony-3.5
$ ./configure --prefix=/usr && make
$ make install
## start chronyd
$ service chrony start
此时在container中运行chrony会报以下错误:
Permission denied
这是因为docker运行container时对权限有所限制,但chrony或ntp的服务需要设置内核时间,它不能运行在有限制的环境中。解决办法,给docker run传递 –privileged参数。
## docker run container with privilege
$ docker run --privileged xxx
参考资料:
Running NTP in a Container: 里面是讨论了ntp在container中的使用,但chrony也是同样的道理。
本文档详述如何在局域网内搭建一个本地的Docker环境来试验OpenStack。首先,通过Apache搭建局域网内的APT源以解决网络问题,接着介绍如何本地编译DEB包,最后探讨建立OpenStack特定的局域网APT源并解决遇到的问题,如locale错误、keystone依赖问题和chronyd/nptd权限问题。
1651

被折叠的 条评论
为什么被折叠?



