本文发布于Cylon的收藏册,转载请著名原文链接~
Prerequisites
- 具有一个 Kubernetes 集群 以部署 Spinnaker
- 可运行 Docker 的环境 (1 vCPU, 3.75 GB) 或者是 Ubuntu,用以安装 Halyard (用于 spinnaker 的服务)
- 对象存储 (MinIO),用于持久化 Spinnaker 的数据
- 对象存储的 Bucket 的访问账号
安装执行步骤
安装 Halyard
可以直接使用 Docker 方式安装,这个没什么必要性,就是管理工具而已,参考附录1 [1]
首先创建映射目录
mkdir ~/.hal -pv
mkdir ~/.kubeconfig -pv
然后执行 docker run 运行容器
docker run -d -p 8084:8084 -p 9000:9000 \
--name halyard --rm \
-v ~/.hal:/home/spinnaker/.hal \
-v ~/.kubeconfig:/home/spinnaker/.kube \
-v /usr/local/bin:/usr/local/sbin \
-v /etc/kubernetes/auth/admin.conf:/home/spinnaker/.kube/config \
us-docker.pkg.dev/spinnaker-community/docker/halyard:stable
因为 docker 环境不能重启服务,需要修改配置文件,这里可以在外部创建一个配置文件来映射进去,这里后面会说到 GCS 的问题
$ docker run -it --rm us-docker.pkg.dev/spinnaker-community/docker/halyard:stable cat /opt/halyard/config/halyard.yml > /tmp/halyard.yml
修改 spinnaker 部分的配置,将 enabled: true
,改为 enabled: false
spinnaker:
artifacts:
debian: https://us-apt.pkg.dev/projects/spinnaker-community
docker: us-docker.pkg.dev/spinnaker-community/docker
config:
input:
gcs:
enabled: false
writerEnabled: false
bucket: halconfig
然后将输出的配置文件保存到宿主机,而后映射到容器内即可
docker run -d -p 8084:8084 -p 9000:9000 \
--name halyard --rm \
-v ~/.hal:/home/spinnaker/.hal \
-v ~/.kubeconfig:/home/spinnaker/.kube \
-v /usr/local/bin:/usr/local/sbin \
-v /etc/kubernetes/auth/admin.conf:/home/spinnaker/.kube/config \
-v /tmp/halyard.yml:/opt/halyard/config/halyard.yml \
us-docker.pkg.dev/spinnaker-community/docker/halyard:stable
安装kubectl
这部分在上一章中注明了挂载 kubectl 的路径
使用 Docker 运行的 Halyard 可以直接挂在 kubectl 到 容器内就可以了,halyard 默认的路径在 /usr/local/bin
只要避免和这个路径冲突就可以了。
halyard 中附带的 kubectl 不一定与你的集群版本一致
最后进入容器就可以管理 spinnaker 了
docker exec -it halyard bash
生成一个 Halyard config [3]
离线安装时,需要生成一个 Halyard config 文件,默认在 ~/.hal/config
hal config version edit --version local:1.19.2
Notes:
- 如果是选择离线安装或者 Local 方式安装,那么 local 关键字必须加
- 如果主机没有网,此时需要指定参数
--no-validate
来控制关闭验证,验证通常要联网- 对于执行大部分的 hal 命令都会在
~/.hal/config
生成配置文件
选择云供应商
这里可以指选择一个 Kubernetes 集群将其添加到 Halyard config 中
注意,这里需要时 Kubectl 可以正常请求集群,即需要 kubectl 与 kubeconfig
但在选择 Kubernetes 作为 Halyard 的 provider 之前,可以在 Kubernetes 中创建一个新的 service 以在 Halyard 中使用。
# Run in Halyard container
CONTEXT=$(kubectl config current-context)
kubectl apply --context $CONTEXT \
-f https://spinnaker.io/downloads/kubernetes/service-account.yml
TOKEN=$(kubectl get secret --context $CONTEXT \
$(kubectl get serviceaccount spinnaker-service-account \
--context $CONTEXT \
-n spinnaker \
-o jsonpath='{.secrets[0].name}') \
-n spinnaker \
-o jsonpath='{.data.token}' | base64 --decode)
kubectl config set-credentials ${CONTEXT}-token-user --token $TOKEN
kubectl config set-context $CONTEXT --user ${CONTEXT}-token-user
启用 kubernetes,并配置使用的 kubernetes 用户
# Run in Halyard container
hal config provider kubernetes enable
ACCOUNT="my-k8s-account"
hal config provider kubernetes account add ${ACCOUNT} \
--context ${CONTEXT}
Halyard 有几种部署 Spinnaker 服务的选项,例如Local, git 和 Distributed,这里使用 Distributed 模式,将 Spinnaker 以分布式方式部署到 Kubernetes内。
hal config deploy edit --type distributed --account-name $ACCOUNT
配置S3存储
Spinnaker 需要外部存储,例如 S3 对象存储置,为此,我使用 Minio 作为外部存储服务。这里使用 docker 进行部署,作为学习,也可以使用 minIO 官方提供的 minIO-dev [4],可以快速在 Kubernetes 集群上部署一个单实例的 minIO
# System
MINIO_ROOT_USER=$(< /dev/urandom tr -dc a-z | head -c${1:-4})
MINIO_ROOT_PASSWORD=$(< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c${1:-8})
MINIO_PORT="9010"
# Start the container
docker run -it -d --rm -v ~/.minio-data/:/data --name minio-4-spinnaker -p ${MINIO_PORT}:${MINIO_PORT} \
-e MINIO_ROOT_USER=${MINIO_ROOT_USER} -e MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD} \
minio/minio server /data --address :${MINIO_PORT}
# This information is used in next {.1}
echo "
MINIO_ROOT_USER=${MINIO_ROOT_USER}
MINIO_ROOT_PASSWORD=${MINIO_ROOT_PASSWORD}
ENDPOINT=http://$(docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' minio-4-spinnaker):${MINIO_PORT}
"
如果需要开启,那么需要在目录 ~/.hal/default/profiles/front50-local.yml
创建文件
spinnaker:
s3:
versioning: false
然后使用以下命令进行配置到 halyard config 文件
ENDPOINT=http://10.0.2.4:9000
MINIO_ACCESS_KEY=minio
MINIO_SECRET_KEY=minio123
echo $MINIO_SECRET_KEY | hal config storage s3 edit --endpoint $ENDPOINT \
--access-key-id $MINIO_ACCESS_KEY \
--secret-access-key
hal config storage edit --type s3
生成一个BOM文件
找一台有外网的主机,执行下列命令
hal version bom 1.19.2 -q -o yaml
Note: 如果开启了
gcs.enabled: true
需要重新启动一个容器,因为这个步骤需要联网查询
$ DOCKERID=`docker run -d --rm \
-v ~/.hal:/home/spinnaker/.hal \
us-docker.pkg.dev/spinnaker-community/docker/halyard:stable`
$ docker exec -it ${DOCKERID} hal version bom 1.19.2 -q -o yaml && docker stop ${DOCKERID}
将输出的文件保存在 halyard 容器内 ~/.hal/.boms/bom/{version}.yml
,将 {version}
替换为你安装的版本,例如这里为 1.19.2
其次,要在本地执行此操作的容器内,需要在 halconfig
目录下有对应的 BOM 清单,清单格式如下:
$ tree ~/.hal/.boms/
/root/.hal/.boms/
├── bom
│ └── 1.19.2.yml
├── clouddriver
│ └── clouddriver.yml
├── deck
│ └── settings.js
├── echo
│ └── echo.yml
├── fiat
│ └── fiat.yml
├── front50
│ └── front50.yml
├── gate
│ └── gate.yml
├── igor
│ └── igor.yml
├── kayenta
│ └── kayenta.yml
├── orca
│ └── orca.yml
└── rosco
└── rosco.yml
这些文件夹需要自行创建,并且里面的配置文件也需要自行创建,如果不知道格式如何,可以参考 Spinnaker github 仓库上,每一个上面的文件夹都是一个项目仓库,而这些仓库的根目录都存在一个 halconfig 目录,此时需要你将对应的文件保存到对应目录下,例如,clouddriver 文件夹需要选择 github.com/spinnaker/clouddriver 项目,而配置文件需要选择 {service_name}.yml
为命名的,例如 clouddriver 就需要选择 clouddriver.yml,这个需要自行下载。
可以使用下列脚本进行生成这些配置文件(需要上网)
#!/bin/bash
####################################################################################
# Install Spinnaker scripts for CentOS #
####################################################################################
set -e
START_TIME=`date +%s`
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
export ROOT=$(cd $(dirname $0); pwd)
export BASE_URL="https://raw.githubusercontent.com/spinnaker"
export DECK_FILE_NAME="halconfig/settings.js"
export FILE_PREFIX="halconfig"
usage(){
cat <<EOF
Usage: $CMD <bom_file> <output_dir>
$CMD ~/.hal/.boms/bom/1.20.0.yml ~/.hal/.boms
EOF
}
function install_json_tools(){
which jq &> /dev/null || sudo yum install jq -y
which yq || ( wget https://github.com/mikefarah/yq/releases/download/v4.16.2/yq_linux_amd64 \
&& chmod +x yq_linux_amd64 \
&& mv yq_linux_amd64 /usr/local/bin/yq )
}
function remove_json_tools(){
rm -f a/usr/local/bin/yq
rpm -e jq --force
}
function pull_packer(){
##check paramter##
if [[ ${#} -ne 1 ]]; then
echo -e "\033[32m Paramter amount error. \033[0m" && exit ${MALFORMEDPARAMTER}
fi
export SPIN_TMP_DIR=${ROOT}/spin_installer
[ -d ${SPIN_TMP_DIR} ] || mkdir -pv ${SPIN_TMP_DIR}
cd ${SPIN_TMP_DIR}
git init
# 配置远程仓库地址
git remote add origin https://github.com/spinnaker/rosco
# 启用 sparse checkout
git config core.sparsecheckout true
# 指定要克隆的目录
echo "halconfig/packer" >> .git/info/sparse-checkout
# 拉取远程仓库的内容
git pull origin ${1}
tar zcf packer.tar.gz -C ./halconfig packer
mv packer.tar.gz ${BOM_PATH_I}/
# clean work dir
cd ${ROOT} && rm -fr ${SPIN_TMP_DIR}
}
function gererate_bom(){
yq eval -o json ${BOM_FILE_NAME} |
jq '.services' |
jq 'del(.defaultArtifact ,.["monitoring-third-party"], .["monitoring-daemon"])' |
jq -r 'to_entries[] | "\(.key)=\(.value)"' |
while IFS="=" read -r key value; do
VERSION="version-`echo $value | jq '.version'|awk -F '=' '{print $1}' | awk -F '-' '{print $1}'| tr -d '"'`"
export BOM_PATH_I=${BOM_PATH}/${key}
[ -d ${BOM_PATH_I} ] || mkdir -pv ${BOM_PATH_I}; chmod 777 ${BOM_PATH_I}
case ${key} in
"deck")
curl "${BASE_URL}/${key}/${VERSION}/${FILE_PREFIX}/settings.js" -o ${BOM_PATH_I}/settings.js
;;
"rosco")
curl "${BASE_URL}/${key}/${VERSION}/${FILE_PREFIX}/${key}.yml" -o ${BOM_PATH_I}/${key}.yml
curl "${BASE_URL}/${key}/${VERSION}/${FILE_PREFIX}/images.yml" -o ${BOM_PATH_I}/images.yml
pull_packer ${VERSION}
;;
*)
curl "${BASE_URL}/${key}/${VERSION}/${FILE_PREFIX}/${key}.yml" -o ${BOM_PATH_I}/${key}.yml
esac
done
chmod 777 ${BOM_PATH} -R
}
function MAIN(){
##check user##
if [[ $UID != 0 ]];then
echo -e "\033[41;05m Sorry, this script must be run as root! \033[0m"
exit ${ILLEGALUSER}
fi
##check paramter##
if [[ ${#} -lt 2 ]]; then
usage && exit ${MALFORMEDPARAMTER}
fi
export BOM_FILE_NAME=$1; shift
export BOM_PATH=$1; shift
##cheking command line##
install_json_tools
##processing bom##
gererate_bom
END_TIME=`date +%s`
EXECUTING_TIME=`expr $END_TIME - $START_TIME`
echo -e "\033[42;30m Time had spent $EXECUTING_TIME seconds. \033[0m"
echo -e "\033[40;34m ######################################################### \033[0m"
echo -e '\n'
}
MAIN $1 $2
在执行脚本时需要在容器运行的宿主机进行,如果这台主机没有网络,那么可以在其他机器执行
额外下载一个 packer.tar.gz
这里 进入文件夹 rosco/master
rosco
有一个文件夹叫packer,这将其移至文件夹并解压缩为 packer.tar.gz
mv ~/.hal/.boms/rosco/master/packer.tar.gz ~/.hal/.boms/rosco
cd ~/.hal/.boms/rosco
tar xvf packer.tar.gz
为BOM服务配置local关键字
对于离线安装,我们需要为 BOM 中的每个服务使用的镜像名称都增加一个 local:
前缀,这是官方的固定格式 [5]
dependencies:
consul:
version: 0.7.5
redis:
version: 2:2.8.4-2
vault:
version: 0.7.0
services:
clouddriver:
commit: 024b9220a1322f80ed732de9f58aec2768e93d1b
version: local:6.4.3-20191210131345
...
配置镜像获取源
这里可以选择 直接 docker 导入镜像到每个 Kubernetes worker 节点上,也可以选择配置私有镜像仓库。
如果需要使用私有镜像,那么需要修改 VERSION.yml
中的dockerRegistry 选项,将其修改为你自己的镜像仓库
artifactSources:
debianRepository: https://dl.bintray.com/spinnaker-releases/debians
#dockerRegistry: gcr.io/spinnaker-marketplace
dockerRegistry: private-docker-registry/repository-name
gitPrefix: https://github.com/spinnaker
googleImageProject: marketplace-spinnaker-release
或者使用 docker save
通过命令导出镜像为 tar.gz
文件,然后导入到所有的 Kubernetes 的工作节点上
部署
可以直接执行 hal deploy
命令可以进行部署,更新,删除等操作
hal deploy apply # 部署
hal deploy clean # 一键清理已经部署的服务
在默认部署情况下,igor 与 fiat 是不开启的,如果你配置了授权与CI的配置,那么会部署上这两个服务sss
这里会生成 Kubernetes 的资源,而手动创建的资源会存在 S3 对象存储中
Troubleshooting
Could not load “versions.yml” from config bucket: xx [2]
这是因为默认情况下从GCS读取配置文件,可以通过修改配置文件 /opt/spinanker/config/halyard-local.yml
关闭 gcs 功能(或 /opt/halyard/config/halyard.yml
)
server:
port: 8064
...
spinnaker:
artifacts:
debian: https://us-apt.pkg.dev/projects/spinnaker-community
docker: us-docker.pkg.dev/spinnaker-community/docker
config:
input:
gcs:
enabled: true
writerEnabled: false
bucket: halconfig
Notes: 修改完成后需要重启进程,并且修改时需要使用root用户进入容器内
docker exec -it 4f3c037d2e3c bash hal shutdown
Unable to retrieve profile “clouddriver.yml”
Validation in Global:
! ERROR Unable to retrieve profile "clouddriver.yml": connect timed out
解决:BOM需要按照固定格式,创建对应每个配置文件的清单
Unable to retrieve profile “versions.yml”
Validation in Global:
! ERROR Unable to retrieve profile "versions.yml": connect timed out
解决:关闭 GCS 即可
No persistent storage type was configured
Validation in Global:
! ERROR No persistent storage type was configured.
解决:hal config storage s3 edit
Error retirveing contentes of archive packer.tar.gz
Validation in Global:
! ERROR Error retirveing contentes of archive packer.tar.gz
解决:拷贝对应服务的 github 仓库中的 packer 文件夹
No profile reader exists to read
! ERROR No profile reader exists to read '6.7.1-20200319123809'.
Consider setting 'spinnaker.config.input.gcs.enabled: true' in
/opt/spinnaker/config/halyard.yml
解决:因为 bom 文件中镜像没有设置 local
Access to XMLHttpRequest at ‘xxx’ has been blocked by CORS policy
如下图所示:
官方给出的检查方法是“排查 gate 服务的可用性” [8],但检查 gate 日志没有问题,service ip 请求也是通的
2023-07-19 15:01:05.150 INFO 1 --- [applications-10] c.n.s.g.s.internal.ClouddriverService : ---> HTTP GET http://spin-clouddriver.spinnaker:7002/applications?restricted=false&expand=true
2023-07-19 15:01:05.186 INFO 1 --- [applications-10] c.n.s.g.s.internal.ClouddriverService : <--- HTTP 200 http://spin-clouddriver.spinnaker:7002/applications?restricted=false&expand=true (31ms)
2023-07-19 15:01:05.227 INFO 1 --- [-applications-9] c.n.s.g.s.internal.Front50Service : <--- HTTP 200 http://spin-front50.spinnaker:8080/v2/applications?restricted=false (83ms)
2023-07-19 15:01:08.343 INFO 1 --- [TaskScheduler-6] c.n.s.gate.plugins.deck.DeckPluginCache : Refreshing plugin cache
2023-07-19 15:01:08.343 INFO 1 --- [TaskScheduler-6] c.n.s.gate.plugins.deck.DeckPluginCache : Cached 0 deck plugins
请求 service ip + port
$ curl 10.111.192.125:8084 -vv
* About to connect() to 10.111.192.125 port 8084 (#0)
* Trying 10.111.192.125...
* Connected to 10.111.192.125 (10.111.192.125) port 8084 (#0)
> GET / HTTP/1.1
> User-Agent: curl/7.29.0
> Host: 10.111.192.125:8084
> Accept: */*
>
< HTTP/1.1 302
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Methods: POST, GET, OPTIONS, DELETE, PUT, PATCH
< Access-Control-Max-Age: 3600
< Access-Control-Allow-Headers: x-requested-with, content-type, authorization, X-RateLimit-App, X-Spinnaker-Priority
< Access-Control-Expose-Headers: X-AUTH-REDIRECT-URL
< X-SPINNAKER-REQUEST-ID: 6b96a924-9bcb-496c-9389-12cc6834aff7
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Location: http://spin-deck.spinnaker:9000
< Content-Length: 0
< Date: Wed, 19 Jul 2023 15:01:28 GMT
<
* Connection #0 to host 10.111.192.125 left intact
浏览器访问 gate url 也是正常的
访问首页提示如下错误,但是单独访问 gate 页面没有问题
报错如下:
Access to XMLHttpRequest at 'http://gate.spinnaker.fuck:30080/credentials?expand=true' from origin 'http://deck.spinnaker.fuck:30080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.Access to XMLHttpRequest at 'http://gate.spinnaker.fuck:30080/credentials?expand=true' from origin 'http://deck.spinnaker.fuck:30080' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
解决:如果使用 Halyard 部署 Spinnaker,则可以使用以下设置创建文件 ~/.hal/default/profiles/gate-local.yml
cors:
allowedOriginsPattern: {you gate url}
Reference
[2] ERROR Could not load “versions.yml” from config bucket: 403 #3920
[3] Spinnaker: How to bring custom boms into spinnaker pod to be able to deploy it with hal?
[4] MinIO Object Storage for Kubernetes
[5] BOMs and Configuration on your Filesystem
[6] ! ERROR No persistent storage type was configured. #5875
[7] Install in Air Gaped Environment
[8] I can’t load the Applications screen
[9] use k8s cluster private, how to access? not use localhost! #4689
本文发布于Cylon的收藏册,转载请著名原文链接~
链接:https://www.oomkill.com/2023/07/offline-installtation/
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」 许可协议进行许可。