[TOC]
概述
这次的实战目标如下:
将已有的python示例程序部署到OpenShift上. 为此, 需要做的事情有:
- 对原有python示例程序做优化和调整, 使得可以部署到OpenShift上.
- 基于OpenShift上自带模板(templates: openshift上的一种CI/CD全流程定义) - Django + PostgreSQL 进行修改生成新的模板.
- 基于新的模板, 填入python示例程序的git地址, 自动进行: 构建(build), 部署(deployment)和对外服务(service, route). 查看部署结果.
OpenShift简介
OpenShift v3(开源版本叫做: okd)是一个PAAS(平台及服务)系统,旨在尽可能准确地公开底层Docker格式的容器镜像和Kubernetes 理念,并着重于开发人员轻松组合应用程序。例如,安装Ruby,推送代码并添加MySQL。
OpenShift基于Docker和Kubernetes, 并针对以下方面进行了开发和优化:
- CI/CD 流程(基于jenkins的pipeline, S2I等)
- UI界面
- 安全加固(如容器内使用非root用户等)
- 监控功能(基于EFK技术栈的日志监控和基于Prometheus的metrics监控等)
- 提供更安全 经过RedHat认证的基础镜像/模板等.(包括: java, python等运行时, mysql, mongo等db, apache, wildfly等中间件, jenkins等CI/CD, elasticsearch, kibana等监控镜像)
:notebook:
OpenShift有多个产品线, 包括:
Python示例程序简介
这是一个Django项目 - Learning Log(《Python编程:从入门到实践》的教学案例),数据库可以基于sqlite或Postgresql.
:notebook:
这个应用的功能如下:
- 这是一个名为"学习笔记"的Web应用程序, 让用户能够记录感兴趣的主题, 并在学习每个主题的过程中添加日志条目.
- "学习笔记"的主页对这个网站进行描述, 并邀请用户注册或登陆.
用户登陆后, 就可以创建新主题/添加新条目以及阅读既有的条目.
实战步骤
python示例程序修改
:notebook:
针对Django应用需要修改的代码其实不多, 都集中在
settings.py
中.
删除heroku部署的相关代码: https://github.com/east4ming/learning_log/commit/1119c62d33766538601a711a4473f0ab64dd8f3e
-
Django
settings.py
文件修改内容:修改
ALLOW_HOSTS
为*
(配置为*
, 表示允许所有hosts, 如果不配置, OpenShift自动分配的域名和地址会无法访问python示例程序): https://github.com/east4ming/learning_log/commit/534c1283eb9c430c1739d71ce0984cee6c776d04DJANGO SECRET 改为通过系统变量(
os.getenv
方式)获取 (OpenShift的原模板 Django + PostgreSQL 包含这一变量): https://github.com/east4ming/learning_log/commit/dd6695db345c333f1d193261fef3a35a2b926c97-
修改
DATABASES
相关代码, 改为兼容sqlite和postgresql. https://github.com/east4ming/learning_log/commit/5dceef61b999cfe0abc45ed371f487c2e428a4c6 新增的database.py
(settings.py
的DATABASES
部分调用该文件)代码如下:import os from django.conf import settings engines = { 'sqlite': 'django.db.backends.sqlite3', 'postgresql': 'django.db.backends.postgresql_psycopg2', } def config(): service_name = os.getenv('DATABASE_SERVICE_NAME', '').upper().replace('-', '_') if service_name: engine = engines.get(os.getenv('DATABASE_ENGINE'), engines['sqlite']) else: engine = engines['sqlite'] name = os.getenv('DATABASE_NAME') if not name and engine == engines['sqlite']: name = os.path.join(settings.BASE_DIR, 'db.sqlite3') return { 'ENGINE': engine, 'NAME': name, 'USER': os.getenv('DATABASE_USER'), 'PASSWORD': os.getenv('DATABASE_PASSWORD'), 'HOST': os.getenv('{}_SERVICE_HOST'.format(service_name)), 'PORT': os.getenv('{}_SERVICE_PORT'.format(service_name)), }
-
(可选) 添加OpenShift相关脚本,变量: https://github.com/east4ming/learning_log/commit/095a59973bc6a6c5886f3debf56dde16e4ef2f96
-
conf/reload.py 用于
APP_CONFIG
变量, 可以调整WSGI相关配置. - openshift/scripts/run-in-container.sh 用于在openshift的部署容器中较为方便地运行一些命令(如创建超级用户等)(不用该脚本, 直接进行容器用shell命令行也是一样的效果)
-
conf/reload.py 用于
针对OpenShift 模板Django + PostgreSQL进行修改生成新模板
:notebook:
关于 OpenShift Templates(模板)的说明, 请参见: https://docs.openshift.com/container-platform/3.11/dev_guide/dev_tutorials/quickstarts.html
模板简介
模板由一组服务(service),构建配置(build config)和部署配置(deployment config)构成。模板引用必要的镜像和源存储库来构建和部署应用程序。
顺便简单介绍一下模板编写时的相关参数:
简单模板示例:
apiVersion: v1
kind: Template
metadata:
name: redis-template
annotations:
description: "Description"
iconClass: "icon-redis"
tags: "database,nosql"
objects:
- apiVersion: v1
kind: Pod
metadata:
name: redis-master
spec:
containers:
- env:
- name: REDIS_PASSWORD
value: ${REDIS_PASSWORD}
image: dockerfile/redis
name: master
ports:
- containerPort: 6379
protocol: TCP
parameters:
- description: Password used for Redis authentication
from: '[A-Z0-9]{8}'
generate: expression
name: REDIS_PASSWORD
labels:
redis: master
描述
模板描述告知用户模板的功能,并帮助他们在Web控制台中搜索时找到它。模板名称之外的其他元数据是可选的,但有用。除了一般描述性信息之外,元数据还包括一组标签(label)。有用的标签包括模板与之相关的语言的名称(例如, java,php,ruby等)。
见上文代码片段的
metadata
部分.
标签
模板可以包含一组 标签。这些标签将添加到实例化模板时创建的每个对象。以这种方式定义标签使用户可以轻松查找和管理从特定模板创建的所有对象。
见上文代码片段的
labels
部分.
参数
参数允许值由用户提供或在实例化模板时生成。然后,只要引用参数,该值就会被替换。可以在对象列表字段的任何字段中定义引用。这对于生成随机密码或允许用户提供自定义模板所需的主机名或其他特定于用户的值非常有用。可以通过两种方式引用参数:
- 通过在模板中的任何字符串字段中以${PARAMETER_NAME}形式放置值来作为字符串值。
- 作为json / yaml值,通过在${{PARAMETER_NAME}}格式中放置值代替模板中的任何字段。
见上文代码片段的
parameters
部分.
对象列表
模板的主要部分是在实例化模板时将创建的对象列表。这可以是任何 有效的API对象,例如 BuildConfig
,DeploymentConfig
,Service
等。该对象将被精确地创建为这里所定义,和在之前的创建取代的任何参数值。这些对象的定义可以引用先前定义的参数.
见上文代码片段的
objects
部分.
修改模板并导入
:notebook:
针对python的官方quickstart模板有3个:
- django (1个pod, 数据库使用sqlite)
- django + postgresql (2个pod, 数据库使用postgresql, 但是数据库数据没有持久化)
- django + postgresql persistent (2个pod, 数据库使用postgresql, 数据库数据进行持久化)
本次使用第三个, 源模板链接:django-postgresql-persistent.json
顺便说明一下, 模板文件几百行, 看起来挺吓人的, 但是实际上大部分都是自动生成的. 可以通过CLI等工具生成, 或者对现成的模板做微调.
修改后的模板django-postgresql-persistent.json. 部分说明:
- 本次模板共创建了以下几类对象:
-
Secret
- 密钥对象(存储加密信息, 本例中存储: 数据库用户名和密码, django secret key) -
Service
- 服务(容器内端口对外暴露并提供负载均衡). 这个模板有2个:- django应用的
Service
- postgresql数据库的
Service
(提供给django使用)
- django应用的
-
Route
- 路由(对外暴露提供服务, 通常是域名) -
ImageStream
- 镜像流(OpenShift特有, 定义如何构建该应用, 包含: 代码库地址, 基础镜像等信息) -
DeploymentConfig
- 部署配置(包含: pod数量及重启策略, 可用性探针, 运行时环境变量, 资源闲置等信息)- django 应用的DC
- postgresql 数据库的DC
-
PersistentVolumeClaim
- 持久性存储声明(包含: 存储大小/读写的声明)
-
- 新增内容:
- 新增
env
和参数:ENABLE_PIPENV
(这个参数基础镜像就有, 这儿列出来设置为true
使之生效)
- 新增
- 修改内容:
- 根据自己的代码仓库信息, 对参数的默认值做了部分修改. (可选, 不修改也行, 填的时候手动填写也可以)
- git仓库相关信息
- pip index url信息(只有使用pip方式才生效, 因为我用的是pipenv方式, 实际上没生效) - 改为阿里的源.
- 基础镜像从python3.5改为了3.6(没啥影响, 只因为我本地用的比较新)
- 对Django pod的可用性探针 -
readinessProbe
和livenessProbe
进行了修改, 改为了自己的测试URI(就是/
), 另外超时时间放长一点.
- 根据自己的代码仓库信息, 对参数的默认值做了部分修改. (可选, 不修改也行, 填的时候手动填写也可以)
- 修改完之后, 导入该模板到OpenShift:
oc create -f .\openshift\templates\django-postgresql-persistent.json
(也可以通过UI导入: Catalog → Custom Add → Import YAML/JSON)
构建 部署并验证应用
-
在OpenShift 的 Catalog页面点击新导入的模板 - Learning Log. 如下图:
-
点击Next:
-
填写相关的配置信息:
-
点击Create. 会自动创建django-psql-persistent应用. 此时, OpenShift会进行如下的动作:
创建PVC
创建Secret
-
创建Build 流程, 我是之前有部分代码有问题, 或者连不上pipenv的源, 构建了4次才成功. (构建也是会启动一个专门的构建容器, 构建成功后输出一个构建后部署的镜像, 同时构建镜像自动销毁). 对于: python pipenv django, build流程大致如下:
- 下载pipenv及相关依赖包(如virtualenv等)
- pipenv根据
Pipfile.lock
安装应用所需依赖包 - Django执行static文件移动和数据库migrate.
- 推送build完成的镜像到镜像库
-
Deployment部署应用, 包括: postgresql和django应用镜像. (pod那个圈是蓝色就是成功了)
- 最终部署成功后, 在OpenShift上的Overview显示如下:
更多细节展示:
容器的环境变量:
容器的日志:
容器的终端:
应用的services:
应用的route:
:thinking:感悟
K8S概念就很复杂了, OpenShift又在这上面添加了很多新概念, 比如: build, S2I, ImageStream ... 真的不容易理解.
还有就是其实开发人员需要频繁调试, 修改代码, 每次修改都得走一遍CI/CD流程. 真的挺耗时的.
目前OpenShift这种容器平台还是需要进一步提升易用性, 毕竟, 开发人员更多精力的是要放在写代码上, 构建部署越便捷越简单越好.
道阻且长啊.