1、前言
准备
问题:Devops适合于中小型团队吗?
我最近花了相当多的时间来思考 “DevOps” 的人员可扩展性,最终得出的结论是,虽然DevOps可以很好地适用于小型工程组织,但这种做法如果没有仔细考虑和管理的话,可以会导致相当大的人力、组织规模问题! 流程很清楚,确实可以自动化完成!
无论 你的项目多小,如果能使用Devops确实能大大减少人力!
本系列核心:
1、深入了解DevOps的思想及落地
2、Jenkins 安装和流水线使用
3、自动化构建任务,实现CI/CD
持续集成
传统的软件开发流程如下:
1、项目经理分配模块给开发人员
2、每个模块的开发人员并行开发,并进行单元测试
3、开发完毕,将代码集成部署到测试服务器,测试人员进行测试
4、测试人员发现bug,提交bug,开发人员修改bug
5、bug修改完毕再次集成,测试。
问题:
1、模块之间依赖关系复杂,在集成时发现大量bug
2、测试人员等待测试时间过长
3、软件交付无法保障
解决上述问题的思考:
1、能否把集成测试时间提前?
2、能否使用自动化工具代替人工集成部署的过程?
持续集成:
持续集成,简称CI,持续集成的思想是:每天要多次将代码合并到主干,并进行集成,测试,这样就可以提早发现错误,进行修正。持续集成也属于DevOps。 小步快跑,快速迭代!=> 将代码提交到gitlab!
持续集成的好处:
1、自动化集成部署,提高了集成效率。
2、更快的修复问题。
3、更快的进行交付。
4、提高了产品质量。
持续集成的流程 开发完毕,直接提交代码,然后等几分钟,”最新项目“ 就上线了!
项目演示!
什么是DevOps?
DevOps是一种思想或方法论,它涵盖开发、测试、运维的整个过程!
DevOps强调软件开发人员与软件测试、软件运维、质量保障(QA)部门之间有效的沟通与协作
强调通过自动化的方法管理软件变更,软件集成
使软件从构建到测试、发布更加快捷、可靠,最终按时交付软件。
公司到底需不需要运维! 基础运维全部被自动替代!IDEA -> Git->通知->平台Docker自动化构建
公司项目开发大概的流程,看看是如何一步一步操作的:Backlog(任务清单)
问题:开发,测试,运维,沟通十分麻烦!(浪费了时间的地方!)
Product Backlog 源自于Scrum方法,是指产品待办事项的集合,其中事务有优先级判断,先处理优先级高的事项。
未来的方向:AI编码+云原生应用为什么当今大公司一定要使用DevOps?
DevOps 这种软件开发方法,涉及到软件整个开发生命周期,这些活动只能在DevOps中实现,而不是敏捷或瀑布流。
DevOps 是在较短的开发周期内开发高质量软件的首选方法,同时可以提高客户满意度。
这就是为什么顶级互联网公司选择DevOps作为其业务目标的前进方向。
如果你是一名开发工程师:学习DevOps,让你成为更加优秀的IT工程师
如果你是一名运维工程师:应用DevOps必将,简化你的工作流程,提高你的工作效率
如果你是一名架构师:DevOps是你在实践中必须拥有的技术能力
如果你是一个跳槽者:了解DevOps必将有助于你找到高薪工作
如何落地实现DevOps这种理念? 4步
DevOps 兴起于2009年,近年来由于云计算、互联网的发展,促进了DevOps的基础设施及工具链的发展,涌现了一大批优秀的工具,这些工具包括开发,测试,运维的各个领域,例如:GitHub,Git/svn,Docker、Jenkins,HudSon,Ant/Maven/Gradle,QUnit、JMeter等,看下图:
==自动化完成这些事情就好了!==
使用Jenkins
环境要求:最低 4G 内存!40G硬盘!
1、编码 => 提交到我们GitHub/GitLab/Gitee
2、GitHub/GitLab => 发起一个通知 Jenkins (WebHook机制)
3、Jenkins 接收通知 => 执行流水线脚本 (一堆命令的集合!)
4、服务就可以自动访问了!
2、Docker回顾安装
Docker 是一个开源的应用容器引擎
诞生于2013年年初,基于Go语言实现,dotCloud公司出品(后改名为 Docker Inc)
Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的Linux机器上。
容器是完全使用沙箱机制,相互隔离
容器性能开销极低
Docker 从17.03 版本之后分为 CE(Community Edition:社区版) 和 EE(Enterprise Edition:企业版) 版本
准备:
1、安装运行Docker
# 1、卸载旧的版本
yum remove docker \
docker-client \
docker-client-latest \
docker-common \
docker-latest \
docker-latest-logrotate \
docker-logrotate \
docker-engine
# 2、环境需求,软件包,仓库
yum install -y gcc
yum install -y gcc-c++
yum install -y yum-utils
# 3、配置镜像地址
yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 4、更新软件索引包
yum makecache fast
# 5、安装docker引擎
yum install -y docker-ce docker-ce-cli containerd.io
# 6、启动docker
systemctl enable docker
systemctl start docker
# 7、运行helloworld镜像测试
docker run hello-world
2、配置镜像加速器
# 1、登录阿里云(容器镜像服务)
# 2、参考配置加速
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://qiyb9988.mirror.aliyuncs.com"]
}
EOF
sudo systemctl daemon-reload
sudo systemctl restart docker
3、关闭防火墙 systemctl stop firewalld.service ,云服务器应该是开通端口安全组
执行流程(架构!脚本的编写,原来全部自己编写的流程,现在全部自动化完成!)
前端和后端应用都可以使用Jenkins自动化部署!
看官方文档学习:https://www.jenkins.io/zh/doc/
3、GitLab安装
github、码云、gitlab!核心是git!
本地的离线存储:不需要网络!私人代码仓库!
Linux上安装gitlab
1、拉取镜像
docker pull gitlab/gitlab-ce
2、数据目录绑定
# etc
mkdir -p /home/gitlab/etc
# data
mkdir -p /home/gitlab/data
# logs
mkdir -p /home/gitlab/logs
3、启动容器(挂载数据)
# 暴露https 443和http 80端口
# 挂载配置文件、数据、日志目录
docker run --name='gitlab' -d -p 4443:443 -p 8888:80 \
-v /home/gitlab/etc:/etc/gitlab \
-v /home/gitlab/data:/var/opt/gitlab \
-v /home/gitlab/logs:/var/log/gitlab \
gitlab/gitlab-ce:latest
# 第1次构建会比较慢,查看gitlab构建过程
docker logs -f gitlab
访问ip:8888,出现以下界面,就可以走下一步,进行克隆地址配置后再创建初始密码
4、先别创建初始密码,先配置git项目访问路径 git clone!
[root@helloworld ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
993e11f205ad gitlab/gitlab-ce:latest "/assets/wrapper" 17 minutes ago Up 17 minutes (healthy) 22/tcp, 0.0.0.0:8888->80/tcp, 0.0.0.0:4443->443/tcp gitlab
进入挂载的配置目录修改gitlab.rb,配置http协议的访问地址,默认是80!如下:
[root@helloworld ~]# cd /home/gitlab/etc
[root@helloworld etc]# vim gitlab.rb
external_url 'http://192.168.56.103'
到进入挂在的data目录,配置git项目拉取的地址,默认是容器名
# /home/gitlab/data/gitlab-rails/etc/gitlab.yml
[root@helloworld data]# cd /home/gitlab/data
[root@helloworld data]# cd gitlab-rails/
[root@helloworld gitlab-rails]# cd etc/
[root@helloworld etc]# vim gitlab.yml
看下面https:false,是使用80端口http协议,如果是true,就是使用443端口https协议,那么上面的gitlab.rb中的external_url
要修改为“ https://192.168.56.103 ”
修改完上面的配置,记得重启容器
[root@helloworld etc]# docker restart gitlab
# 启动过程中查看日志
[root@helloworld etc]# docker logs -f gitlab
重新访问ip:8888,进入创建初始密码界面,ip和端口根据自己的服务器修改
5、登录gitlab,默认用户是root,然后测试创建拉取项目!
点击Sign in
点击Create a project
6、如果能够成功拉取到本地就没有问题!
注意我们是使用8888端口映射容器的80端口的,所以克隆地址要加上8888端口,尝试在本地是否能把项目克隆下来
Mac上安装gitlab
先安装Docker,再安装gitlab是一样的套路
4、Jenkins的安装使用
Jenkins 是什么?
Jenkins是一款开源 CI&CD 软件,用于自动化各种任务,包括构建、测试和部署软件。
Jenkins 支持各种运行方式,可通过系统包、Docker 或者通过一个独立的 Java 程序。
1、系统包 war ` /usr/share/jenkins/jenkins.war`
2、Docker (推荐选择),如果docker连不到网络,重启docker
systemctl restart docker
安装jenkins
官网:https://www.jenkins.io/zh/doc/book/installing/
1、准备
jenkins 是一个独立的应用!
磁盘要求
- 256MB可用内存
- 1GB可用磁盘空间(作为一个Docker容器运行jenkins的话推荐10GB)
- 为小团队推荐的硬件配置 :
- 4GB+可用内存
- 50 GB+ 可用磁盘空间
建议使用的Docker映像是jenkinsci/blueocean
image(来自 the Docker Hub repository)。 该镜像包含当前的长期支持 (LTS) 的Jenkins版本 (可以投入使用) ,捆绑了所有Blue Ocean插件和功能。这意味着你不需要单独安装Blue Ocean插件。
默认的 jenkins镜像两年前就不维护了!下面这个不要安装
jenkins/jenkins latest 6328c71fe374 2 days ago 659MB
Blue Ocean 是一个可视化插件,更加好看和智能!
2、安装jenkins
# 1、挂载目录和docker容器内同步!
mkdir -p /var/jenkins_home
chmod 777 /var/jenkins_home
# 2、run
docker run \
-u root \
-d \
-p 8080:8080 \
-p 50000:50000 \
-v /var/jenkins_home:/var/jenkins_home \
-v /var/run/docker.sock:/var/run/docker.sock \
--name jenkins \
jenkinsci/blueocean
3、等待启动成功,访问 Ip:8080 !
需要登录密码(1、logs 日志,2、默认配置文件中查看密码)
# 查看容器的日志
docker logs -f jenkins
输入密码,点击“继续”,进入到安装插件页面,先设置国内加速地址后再安装插件
4、Jenkins是有众多的插件组装而成,安装插件,默认是从国外下载!!
# 插件下载慢,配置updates加速地址
cd /var/jenkins_home/updates
# 执行脚本如下
#把 “ www.google.com ” 改成 “ http://www.baidu.com/ ”
#全局搜索 “ updates.jenkins-ci.org/download ” 替换成 mirrors.tuna.tsinghua.edu.cn/jenkins
sed -i 's/http:\/\/updates.jenkins-ci.org\/download/https:\/\/mirrors.tuna.tsinghua.edu.cn\/jenkins/g' default.json && sed -i 's/http:\/\/www.google.com/https:\/\/www.baidu.com/g' default.json
# 注意:不用重启jenkins
5、如果你手多重启了,重启之后会发现,登录页面没了,插件页面没了,这个时候,我们就需要重装一下!
[root@helloworld updates]# docker rm -f -v jenkins
# 删除挂载的目录
[root@helloworld var]# rm -rf jenkins_home/
6、配置完加速地址后,新手选择“安装推荐插件”,老手选择“选择插件安装”
等待安装的过程发现安装的特别慢,超过2分钟第一行还没绿,直接重装,清除数据,重新配置 updates加速地址!
7、安装成功,创建管理账号,然后就成功了!
点击保存并完成就行,然后就是重启jenkins让部分插件生效
页面相关知识
url重启Jenkins:ip:8080/restart
登录界面,中文支持,配置项!
1、用户列表
2、构建历史
3、系统管理,最重要的页面
-
系统管理->插件管理->设置 ->插件地址(经常用) 安装可视化插件blue ocean
安装插件Gitee 码云
安装插件Gitlab
选择直接安装
-
系统管理->系统信息
4、成员视图配置,新建视图
5、我们之后使用 blue ocean 界面!下载对应插件即可!
5、Pipeline
5.1 hello-jenkins
什么 Pipeline ? 流水线! 编码=> 推送到远程=> 测试=> 环境部署=> 打包上线……(一些列流程的集合!shell)
就是落地实现Devops的第3步:Jenkins 接收gitlab通知 => 执行流水线脚本 (一堆命令的集合!)
1、创建一个流水线任务
2、编写脚本
Jenkinsfile
,定义流水线的脚本文件!参考官网https://www.jenkins.io/zh/doc/pipeline/tour/hello-world/创建你的第一个pipeline
# pipeline 中的步骤,jenkins会帮我们自动完成!@
pipeline {
agent { docker 'maven:3.3.3' } # 环境
stages { # 具体的构建
stage('build') { # 大步骤:开发、测试、部署
steps { # 小步骤:每一个命令!
sh 'mvn --version'
}
# 之后我们需要编写的步骤,都在这里编写即可!
}
}
}
3、点击应用,保存!返回工作台,看到任务hello-jenkins
你可以点击“立即构建”,或者点击“打开Blue Ocean”进入Blue Ocean 界面后点击“运行” ,是一样的效果,经典界面与Blue Ocean界面,
点击绿色的 打勾,看到更详细的运行过程
上面相当于在linux执行脚本
需要修改pipeline 脚本,下拉菜单中点击“配置”
5.2 多步骤的程序如何构建
官网例子:https://www.jenkins.io/zh/doc/pipeline/tour/running-multiple-steps/
pipeline {
agent any # 任何环境!
stages {
stage('构建') {
steps {
sh 'echo "Hello World"'
# 输入多个语句执行,shell脚本
sh '''
echo "Multiline shell steps works too" # 第一个语句
ls -lah # 第二个语句
'''
}
}
}
}
点击“配置”修改pipeline脚本,点击“应用”-》“保存”
回到blue ocean 界面点击“运行”即可
运行成功
5.3 定义执行环境
每个示例中的 agent
指令。 agent
指令告诉Jenkins在哪里以及如何执行Pipeline或者Pipeline子集。 正如您所预料的,所有的Pipeline都需要 agent
指令。
在执行引擎中,agent
指令会引起以下操作的执行:
-
所有在块block中的步骤steps会被Jenkins保存在一个执行队列中。 一旦一个执行器 executor 是可以利用的,这些步骤将会开始执行。
-
一个工作空间 workspace 将会被分配, 工作空间中会包含来自远程仓库的文件和一些用于Pipeline的工作文件
# 进入挂载目录jenkins_home, [root@helloworld ~]# cd /var/jenkins_home/workspace/ [root@helloworld workspace]# ls hello-jenkins hello-jenkins@tmp
小技巧:如果未来项目报错了,来workspace目录找对应的项目文件
规则参考:https://www.jenkins.io/doc/book/pipeline/syntax/#agent
agent
指令更多选项和相关信息,可以查看 语法参考 。
any (常用)
none
label
node
docker (常用)
dockerfile
kubernetes
环境和步骤,我们可以搞定了!
5.4 环境变量
pipeline {
agent any
# 如果要定义自己的环境变量,我们可以在这里配置,自动部署的,环境的部署!
environment {
JAVA_HOME = '/usr/local/java'
DISABLE_AUTH = 'true'
DB_ENGINE = 'sqlite'
}
stages {
stage('Build') {
steps {
sh 'printenv' # 打印所有的环境变量
}
}
}
}
运行
5.5 善后(记录测试和构建结果)
pipeline {
agent any
stages {
stage('No-op') {
steps {
sh 'ls'
}
}
}
# 结束之后执行什么!在整个构建过程中,做一些事情!
post {
# 总是执行,构建后都会执行
always {
echo 'One way or another, I have finished'
deleteDir() /* clean up our workspace */
}
# 成功之后执行
success {
echo 'I succeeeded!'
mail to: '747463168@qq.com',
subject: "构建成功: ${currentBuild.fullDisplayName}",
body: "hello-jenkins运行成功了 ${env.BUILD_URL}"
}
# 不稳定的状态
unstable {
echo 'I am unstable :/'
}
# 失败,部署!失败进行清理文件数据等
failure {
echo 'I failed :('
}
# 改变
changed {
echo 'Things were different before...'
}
}
}
运行该脚本
5.5 发送邮件
官方文档:https://www.jenkins.io/zh/doc/pipeline/tour/post/
前提是Jenkins已安装email插件
pipeline {
agent any
stages {
stage('Test') {
steps {
sh './gradlew check'
}
}
}
post {
failure {
mail to: 'team@example.com',
subject: "Failed Pipeline: ${currentBuild.fullDisplayName}",
body: "Something is wrong with ${env.BUILD_URL}"
}
}
}
如果指令失败,或者网络问题,那么我们结束构建!后置处理,放在post标签的failure 进行处理
5.6 部署流程
官方文档:https://www.jenkins.io/zh/doc/pipeline/tour/deployment/
大多数最基本的持续交付 Pipeline 至少会有三个阶段:构建、测试和部署
pipeline {
agent any
stages {
stage('Build') {
steps {
echo 'Building'
}
}
stage('Test') {
steps {
echo 'Testing'
}
}
stage('Deploy') {
steps {
echo 'Deploying'
}
}
}
}
点击“运行”,流程是这个样子
5.7 人工确认
官方文档:[https://www.jenkins.io/zh/doc/pipeline/tour/deployment/](
通常在阶段之间,特别是不同环境阶段之间,您可能需要人工确认是否可以继续运行。 例如,判断应用程序是否在一个足够好的状态可以进入到生产环境阶段。 这可以使用 input
步骤完成。 在下面的例子中,“Sanity check” 阶段会等待人工确认,并且在没有人工确认的情况下不会继续执行。
pipeline {
agent any
stages {
stage('Deploy - Staging') {
steps {
echo 'Building'
}
}
stage('Sanity check') {
steps {
input "Does the staging environment look ok?"
}
}
stage('Deploy - Production') {
steps {
echo 'Building'
}
}
}
}
效果,如果用户点击ok,那么我们执行,否则不执行,跳过!
6、WebHooks
无论是码云。还是github、还是gitlab。都有webhook?
什么是 webhook? 我们提交代码或者更新了仓库中的内容,可以触发一个事件,接收到这个事件!
码云的webhooks
登录码云,打开一个仓库,点击管理,会看到webhooks,点击“添加”,POST地址是公网的
Github的webhooks
Gitlab的webhooks
进入项目
点击“Settings”,找到Webhooks
测试webhook通知机制!
目的: git仓库发现变化,自动通知jenkins来执行!
登录自己的gitlab仓库
1、创建项目hello-jenkins ,确定gitlab仓库可用
2、jenkins配置触发器(核心!)
进入任务 hello-jenkins,点击配置,找到“构建触发器”
构建触发器,有多种选择
-
其他工程构建后触发
-
定时构建,写cron表达式
-
Gitlab webhook
-
我们通常和github、gitlab来绑定!
如果你这里没有对应的插件,那么就会找不到,然后需要去插件管理中下载!
安装gitlab的所有插件
3、构建触发器,我们使用Gitlab webhook的方式 ,得到jenkins hook地址和生成的授权密钥,填写到Gitlab的Webhooks上
第1步:配置Gitlab的Webhook
jenkins配置 点击“应用”
GitLab上点击“Add Webhook”
如果出现了下面的报错接不上
GitLab需要配置允许所有网络访问,记得点击 “Save Change ”
配置生效后
第2步:测试触发
在项目上添加一个文件
在GitLab的webhooks,点击“Push event”
push 成功,会提示“Hook executed successfully: HTTP 200”
回到Jenkins,查看任务hello-jenkins,发现已自动构建,仓库发生变化就会触发Jenkins自动构建
结论: 如果Gitlab触发成功,Jenkins收到事件,那么就会自动构建!之后,只要我们的仓库,有动静,那么Jenkins就会自动构建!
注意: 失败,hook连接不上,网络配置! 阿里云+github/gitee,只要保证端口开放即可!
7、流水线实战
Docker + Dockerfile + DockerCompose(Docker Swarm架构,使用docker stack 命令上线)
补充:课后练习,集群的时候可以使用 docker stack deploy部署项目!
DockerCompose.yml => docker-compose up 上线,可以构建镜像
DockerCompose.yml => docker stack deploy -f DockerCompose.yml 集群上线!只能使用现成的镜像!
version: "3.8"
services: # 每个服务,可以动态扩容
redis:
image: redis:alpine
deploy: # 集群 docker stack deploy 才会生效,集群!
replicas: 6 # 副本数!
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
项目push到gitlab
计数器 springboot + redis
1、创建Springboot项目
增加阿里云仓库配置文件setting.xml
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
<mirrors>
<mirror>
<id>nexus-aliyun</id>
<mirrorOf>central</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/repositories/central</url>
</mirror>
</mirrors>
</settings>
编写项目流水线文件Jenkinsfile
pipeline {
agent {
docker {
image 'maven:3-jdk-11' # 不要使用 apl 压缩的,很多动态链接库不包含
args '-v /root/.m2:/root/.m2'
}
}
stages {
stage('打包项目') {
steps {
sh 'mvn -B -gs settings.xml -DskipTests clean package' # 指定maven仓库为aliyun
}
}
stage('环境安装') {
steps {
sh 'curl -L https://get.daocloud.io/docker/compose/releases/download/1.25.5/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose'
sh 'chmod 777 /usr/local/bin/docker-compose'
sh 'docker-compose version'
sh 'docker-compose down' # 先把项目下线
}
}
stage('部署上线') {
steps {
sh 'docker-compose up --build'
}
}
}
}
2、Gitlab创建仓库项目New project
3、得到仓库地址
git clone http://139.199.13.139:8888/root/compose-web.git
cd compose-web
touch README.md
git add README.md
git commit -m "add README"
git push -u origin master
克隆gitlab项目仓库,将.git文件放到项目根目录下,将代码push上去,小技巧:可以在新目录下git clone,然后直接将.git文件移动到项目的根目录下
推送代码,左上角的commit, push
登录Gitlab,查看代码
项目构建完毕,下面配置自动化流程!
配置Jenkins
登录Jenkins
1、新建一个任务
2、代码和流水线文件来自git!
选择Jenkins
选择凭据,填写Jenkinsfile的脚本路径
3、构建触发器
点击“应用”,然后到Gitlab上添加webhook 触发构建任务
4、Gitlab上添加webhook
测试
先手动自己运行构建任务,看是否成功,后期再通过提交代码到gitlab,webhook触发自动构建
部署上线失败
解决:
修改Dockerfile
FROM java:8
COPY target/*.jar /app.jar
CMD ["--server.port=8080"]
EXPOSE 8080
ENTRYPOINT ["java","-jar","/app.jar"]
修改docker-compose.yml
version: '3.8'
services:
compose-web:
build: .
image: "compose-web"
depends_on:
- redis
ports:
- "8090:8080"
redis:
image: "redis:alpine"
commit and push 代码,gitlab通过webhook机制通知jenkins自动构建部署项目。
访问请求
持久化的数据,数据库,redis,maven依赖,尽量挂载同步到我们的本地!
这里就是我们最开始演示的步骤了!
如果是网络问题,参考我们今天开始的时候演示的时候的解决办法!
问题:容器内断网了!
解决:重启docker,重启容器!
# 停掉所有容器
docker stop $(docker ps -qa)
# 重启docker
systemctl restart docker
假设出现了问题,文件丢失,不正确,你就可以来这个 workspace查看!
[root@helloworld ~]# cd /var/jenkins_home/workspace/
[root@helloworld workspace]# ls
compose-web compose-web@tmp hello-jenkins@tmp
总结
1、docker 集群使用swarm的话,那么jenkins应该安装在一个manager节点上,执行脚本从代码仓库拉取代码重新构造镜像后,使用docker service 命令灰度发布服务。
作业
1、自己尝试自动构建3个以上的项目 Jenkinsfile (shell学起来!)
shell菜鸟教程https://www.runoob.com/linux/linux-shell.html