Docker折腾记: (1)构建yapi容器,从构建发布到可用

5,902 阅读12分钟

前言

yapi是什么?

YApi 是一个可本地部署的、打通前后端及QA的、可视化的接口管理平台 yapi.ymfe.org

文章会穿插部分相关的知识点,可以节省你爬坑的时间,都是一步一步爬出来的,

从定制构建的思路,优化,实现的姿势, 感兴趣的小伙伴往下走~~~

效果图

登录

登录成功

项目区域

yapi容器

已经内置了bash为默认shell,vim也配置了一些常用的设置

  • vim的预设

前置基础

知识储备

Docker/Linux/Node基础, 比如Linux和docker的常用命令,shell的编写等等

构建基础环境

  • Docker version 18.03.1-ce
    • 基于alpine ,alpine是一个非常轻量级的Linux,裸版本只有5M
  • Docker Compose(从 pip3 安装的默认版本)

构建的目标: 能用/能升级,数据库独立,第一次构建是拉取最新的版本!!!!

实用科普

若是走Docker Hub自动化构建,因为是在国外服务器构建,不存在慢的问题,

下面的仅限于你本地构建的时候采纳

众所周知国外的资源都比较慢,所以我们构建优先选择境内提供的

Docker中国源:

Linux镜像源用的科大源

alpine的仓库列表,官方的且支持查询

隔天同步Github的码云

尽可能最小化配置,所以不配置什么个性化的东西了,比如oh my zsh,neovim这些

通过这篇文章,你能大体学会docker的简单部署,基本的dockerfile编写, 以及如何发布自己定制化的容器

我提供的yapi 镜像走自动化构建,所以内部依赖的还是国际源,不在本地打包,不会有慢之说

所以要拉取的小伙伴,只要考虑docker拉取源就行啦

常规构建yapi

我这里选择的是基于alpine来构建, 构建的姿势很多,

你可以从一个空容器也能从别人打包好的node容器

镜像的功能尽可能保持单一化,这样有利于编排,

若是一个镜像提供多个服务,维护起来是比较麻烦的.

特别是更新亦或者需要暂停某些服务的时候,要考虑的东西很多

版本一:中规中矩

Dockfile

# 基于 alpine镜像构建
FROM alpine:3.8
# 镜像维护者的信息
LABEL MAINTAINER = 'crper@outlook.com(https://github.com/crper)'
# 基础环境构建
# - 替换国内源,速度杠杠的
# - 更新源
# - 安装基础环境包
# - 更改用户的默认shell , 因为容器只是给yapi用,所以就不考虑创建用户组和独立用户这种东西,所以只有root用户了
#   ,若是容器包括多功能就需要用户组这些好一些(不推荐容器有太多功能),尽可能保持容器功能的单一性
# - 最后是删除一些缓存
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories \
  && apk update \
  && apk add --no-cache shadow git nodejs nodejs-current-npm bash vim tar curl python python-dev py-pip gcc libcurl make\
  && usermod -s /bin/bash root \
  && rm -rf /var/cache/apk/*
# 克隆项目以及初始化项目
# yapi 官方的内网部署教程: https://yapi.ymfe.org/devops/index.html
# install-server会初始化数据库索引和管理员账号,管理员账号名可在 config.json 配置
RUN npm i -g node-gyp --registry https://registry.npm.taobao.org \
  && npm install -g yapi-cli --registry https://registry.npm.taobao.org \
  && mkdir /yapi && cd /yapi \
  && git clone https://github.com/YMFE/yapi.git vendors  \
  && cd vendors \
  && npm install --production --registry https://registry.npm.taobao.org
# 工作目录
WORKDIR /yapi/vendors
# 配置yapi的配置文件
COPY config.json /yapi/
# 复制执行脚本到容器的执行目录
COPY entrypoint.sh /usr/local/bin/

# 向外暴露的端口
EXPOSE 3000

# 指定配置文件
ENTRYPOINT ["entrypoint.sh"]



entrypoint.sh


#!/bin/sh

# yapi初始化后会有一个init.lock文件
lockPath="/yapi/init.lock"

# 如果初始化文件文件存在,则直接运行,否则初始化
if [ ! -f "$lockPath" ]; then
  node /yapi/vendors/server/install.js
else
  node /yapi/vendors/server/app.js
fi

.dockerignore

这个文件是个好东西,跟.gitignore类似的,就是专门用来忽略提交文件的,不至于让我们镜像带上一些不必要的东西

.git/
node_modules/

本地打包镜像后才发现,虽可以用,但有两个问题暴露出来(体积,构建速度)

所以我考虑下能不能优化,

版本二:减小镜像体积,减少构建时间

选一个好的父容器,一个是减少构建的层数,一个是减少依赖包

第一步不能改了,虽然也有node-alpine这些,只能从后面两个入手

Dockfile


# 基于 alpine镜像构建
FROM alpine:3.8
# 镜像维护者的信息
LABEL MAINTAINER = 'crper@outlook.com(https://github.com/crper)'
# 基础环境构建
# - 替换国内源,速度杠杠的
# - 更新源
# - 安装基础环境包
# - 更改用户的默认shell , 因为容器只是给yapi用,所以就不考虑创建用户组和独立用户这种东西,所以只有root用户了
#   ,若是容器包括多功能就需要用户组这些好一些(不推荐容器有太多功能),尽可能保持容器功能的单一性
# - 最后是删除一些缓存
# - 克隆项目
# !! yapi 官方的内网部署教程: https://yapi.ymfe.org/devops/index.html
RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories \
  && apk update \
  && apk add --no-cache shadow git nodejs nodejs-current-npm bash vim tar curl python python-dev py-pip gcc libcurl make\
  && usermod -s /bin/bash root \
  && rm -rf /var/cache/apk/* \
  && mkdir /yapi && cd /yapi && git clone https://gitee.com/mirrors/YApi.git vendors
# 工作目录
WORKDIR /yapi/vendors
# 配置yapi的配置文件
COPY config.json /yapi/
# 复制执行脚本到容器的执行目录
COPY entrypoint.sh /usr/local/bin/
# 写好的vim配置文件复制进去
COPY .vimrc /root/
# 向外暴露的端口
EXPOSE 3000

# 指定配置文件
ENTRYPOINT ["entrypoint.sh"]


# `shadow`: `alpine`默认不集成`usermod`,所以需要这个额外包,因为要用来更改默认`shell`
# `vim` : 编辑神器
# `tar` : 解压缩
# `make`: 编译依赖的
# `gcc`:  GNU编译器套装
# `python`: `python python-dev py-pip`这三个包包括了基本开发环境
# `curl` 可以测试连接也能下载内容的命令行工具
# `git` : 不用说了
# `nodejs` : node
# `nodejs-current-npm` : `alpine`Linux版本需要依赖这个版本,才能让`npm`识别到

entrypoint.sh

#!/bin/sh

# yapi初始化后会有一个init.lock文件
lockPath="/yapi/init.lock"

# 设置源为淘宝源
npm config set registry http://registry.npm.taobao.org/;

# 进入yapi项目
cd /yapi/vendors


# 如果初始化文件文件存在,则直接运行,否则初始化
if [ ! -f "$lockPath" ]; then
  # 全局安装用来更新yapi的cli
  npm i -g node-gyp yapi-cli;
  # 安装初始化的依赖模块
  npm i --production;
  # 启动Yapi初始化
  node server/install.js
else
  node server/app.js
fi

从500多M的镜像减小到400出头,百分之二十还是挺可观,能不能再优化下呢!!!

vim,tar,bash,shadow,py-pip都能去掉了,其他都是构建需要的(比如yapi初始化依赖python这些)

emm..... 去掉了这些,打包出来就减少了40多M,还是还原吧,优化下构建时间

版本三: 降低初始化失败的概率

因为用了dockerhub 的自动化构建,所以npm直接在构建的时候选择官方源

Dockerfile

# 基于 alpine镜像构建
FROM alpine:latest
# 镜像维护者的信息
LABEL MAINTAINER = 'crper@outlook.com(https://github.com/crper)'
# 基础环境构建
# - 更新源
# - 安装基础环境包
# - 不用更改默认shell了,只要进入的镜像的时候指定shell即可
# - 最后是删除一些缓存
# - 克隆项目
# - 采用自动化构建不考虑国内npm源了 , 可以降低初始化失败的概率
# !! yapi 官方的内网部署教程: https://yapi.ymfe.org/devops/index.html
RUN apk update \
  && apk add --no-cache  git nodejs nodejs-current-npm bash vim  python python-dev gcc libcurl make\
  && rm -rf /var/cache/apk/* \
  && mkdir /yapi && cd /yapi && git clone https://github.com/YMFE/yapi.git vendors \
  && npm i -g node-gyp yapi-cli \
  && cd /yapi/vendors && npm i --production;
# 工作目录
WORKDIR /yapi/vendors
# 配置yapi的配置文件
COPY config.json /yapi/
# 复制执行脚本到容器的执行目录
COPY entrypoint.sh /usr/local/bin/
# 写好的vim配置文件复制进去
COPY .vimrc /root/
# 向外暴露的端口
EXPOSE 3000

# 指定配置文件
ENTRYPOINT ["entrypoint.sh"]


# `vim` : 编辑神器
# `tar` : 解压缩
# `make`: 编译依赖的
# `gcc`:  GNU编译器套装
# `python`: `python python-dev py-pip`这三个包包括了基本开发环境
# `curl` 可以测试连接也能下载内容的命令行工具
# `git` : 不用说了
# `nodejs` : node
# `nodejs-current-npm` : `alpine`Linux版本需要依赖这个版本,才能让`npm`识别到

entrypoint.sh

#!/bin/sh

# yapi初始化后会有一个init.lock文件
lockPath="/yapi/init.lock"



# 进入yapi项目
cd /yapi/vendors


# 如果初始化文件文件存在,则直接运行,否则初始化
if [ ! -f "$lockPath" ]; then
  # 启动Yapi初始化
  node server/install.js
else
  # 运行yapi管理系统
  node server/app.js
fi

打包镜像

格式: docker build [option] tagName path

docker build -t yapi .;

默认不带:来独立版本号,打包出来为latest

这里的意思就是在当前目录下,基于Dockfile构建一个镜像,

你也可以自己构建你的维护版本号,比如

docker build -t yapi:0.0.1 .

若需要压缩镜像为gz格式,带上--compress

发布镜像

常规终端手动发布

登录账号

这里的账号就是docker官方注册的账号,整体的过程很类似git

  • 打开终端-> docker login

  • commit:提交你自己写的或者二次定制的镜像

规格: docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] [flags]

  • push : 推送镜像到远程docker hub , 啊咧,报错了?

提示我们没有权限,为什么会有这个问题,

docker hub的提交规范需要我们用自己用户名开头,改一下即可

版本一的镜像体积

版本二的镜像体积

我提交的compress的版本,所以你在docker hub看到只有这么大

走完这一步,你的作品就可以在Dock Hub看到了

你可以直接基于本地构建的镜像搭建了,

若是你基于你自己的包再做二次构建,不需要走commit那一步也可以的,改完直接push就行了

自动化构建发布

Docker Hub提供了automated build,简言之就是自动化构建,

我们可以关联github仓库来构建,bitbucket也可以,但是我不用这个;

不管是从这里还是从用户管理那里,都需要提前绑定github(授权)

授权后,就能读取到你的仓库列表.选择一个仓库来构建,仓库的要求,基本目录如下

├── .dockerignore  //docker打包忽略的文件
├── .gitignore     //git提交忽略的文件
├── Dockerfile     //docker 构建配置文件
├── README.md      // 不用多说了
├── config.json    // yapi的配置文件
└── entrypoint.sh   // 构建入口的脚本

初始化可以设置那些分支会触发构建,亦或者触发endpoint来构建, 最傻瓜化的就是勾选监听push事件自动构建

若是你想把镜像上传到国内的阿里云,dao这些,

有些需要注册开发者账号,根据他们的文档要求来提交

镜像部署

写完的作品没法部署那就搞笑了,现在跟着我来部署你的镜像以及初始化;

部署yapi

第一次初始化默认拉取的最新的版本,所以不用指定版本,

若是yapi代码不严谨,连新版本初始化都会报错则无解!

创建volume

  • docker volume create yapi-mongo

创建一个储存卷,用来专门存放yapi使用的mongodb的数据

为什么要独立出来,这是为了以后升级的着想,数据库保留,只要启动的时候关联一下就行了

启动mongodb

  • docker run -d --name yapi-mongo -v yapi-mongo:/data/db mongo

为什么要先启动mongodb,因为yapi初始化的时候依赖mongodb,比如创建用户表这些

这条命令是什么意思呢?


-d : 是启动的时候输出容器的id
--name : 是给容器设置一个名字,方便我们控制,比如start,stop
-v : 指定关联的卷 => 本地卷:容器内储存位置 , 就是映射数据保存的地方

若是需要外部管理这个数据库的话,最好也暴露出来端口, mongodb容器默认也暴露了27017端口

  • docker run -d --name yapi-mongo -v yapi-mongo:/data/db -p 27017:27017 mongo

初始化Yapi和启动Yapi

  • 初始化yapi

docker run -d --name yapi -p 3000:3000 --link yapi-mongo crper/yapi

这里比上面多的一个参数就是--link,用来使连个容器通讯的,过时命令,官方已经不推荐

  • 启动yapi

docker restart yapi

过程均可用docker logs details 容器ID或者name来看到内部的情况

就是shell执行过程,比如这个项目就可以在初始化的时候,看到初始化的账号密码(成功)

不管是mongo还是crper/yapi ,当你请求一个容器不存在的时候,

会尝试往dockhub上面找,默认拉取镜像latest版本,找不到才会报错

以下就是基本的初始化信息

访问链接: 127.0.0.1:3000
默认的账户名: config.json =>  adminAccount 这个字段的值
密码: ymfe.org

-----而可能发生的错误,就是npm挂了------

在初始化的时候,执行

docker logs --details 容器ID

查看内部终端的执行过程,npm的一些源也不一定靠谱,

若是提示npm安装报错了,就需要进去换其他源了

先启动crper/yapi镜像,然后跟着教程走

// npm config set registry [url]
// npm ---- https://registry.npmjs.org/
// cnpm --- http://r.cnpmjs.org/
// taobao - http://registry.npm.taobao.org/
// eu ----- http://registry.npmjs.eu/
// au ----- http://registry.npmjs.org.au/
// sl ----- http://npm.strongloop.com/
// nj ----- https://registry.nodejitsu.com/


// 进入到vendors目录
// 若是有node_modules目录,
// 我们都应该先干掉node_modules
// 这样重新安装依赖才会比较干净

// 进到vendors目录, 比如设置回官方源
npm config set registry https://registry.npmjs.org/;

// 安装全局升级工具和依赖编译的npm模块
npm i -g node-gyp yapi-cli \
npm i --production;

// 初始化 yapi
node server/install.js

依赖安装完成就可以再重新初始化,然后重启容器即可

进入容器操作

  • docker ps : 从这个看到你的镜像运行容器的信息列表
  • docker exec -it 容器ID bash : 这句话就是非侵入式的进入容器内部,并且调用的shellbash,这个exit不会干掉容器

docker attach这个命令慎用,会在终端退出的会把容器停止,这条命令是看情况使用的!!!!

升级yapi

因为不涉及到容器处理..只是单纯的文件替换,官方也提供了方案,那个cli已经默认集成到容器里面

// https://yapi.ymfe.org/devops/index.html
cd  {项目目录}
yapi ls //查看版本号列表
yapi update //升级到最新版本
yapi update -v v1.1.0 //升级到指定版本

升级完毕重启node程序亦或者重启容器即可!!

Github地址: yapi-docker

GUI管理数据库

我们暴露了27017端口,所以我们宿主机可以用工具链接到数据库内部,

萝卜青菜各有所爱,效果图

喜欢用命令行的也一样

错误汇总

构建yapi过程发生的一些错误

  • /bin/sh: npm: not found , 构建的时候安装nodejs-current-npm
  • usermod not found : 构建的时候安装shadow
  • gyp ERR! stack Error: Can't find Python executable "python", you can set the PYTHON env variable.
    • 这个是初始化yapi遇到的,需要补全python的基础环境,构建的时候加入相关安装包
  • mongodb没法访问,就是当你配置文件设置127.0.0.1的时候..
    • docker中,容器名默认映射容器的访问ip,所以config.json必须指定为mongo的容器名(这个坑浪费了贼多的时间,国外的社区都搜罗了一遍,基本都是说什么--network这些)

还有一些错误忘记截图收录了

------------温馨提示------------

为什么看到的dockerfile用了大量的\来链接命令 ,

那是因为RUN一次是构建一个镜像,再以此为基础传递给下面二次编排,

若是里面大量的使用了RUN,那就相当于你这个镜像从头到尾要构建很多层(体积也会变大)...官方推荐是不超过七层!!

构建层目前最多不能超过127层!

对于--link来链接容器(互相访问),这个docker官方已经不推荐了,属于过时特性,新的网络模式很健全,

提供了桥接,宿主,子网这些模式,但是这些并不适用于--link结合

所以,对于多容器的编排,更推荐用docker-compose来配置,可配置的东西贼多而且好维护,比如最新的3.6版本

传送门: docs.docker.com/v17.09/comp…

总结

写这文章各种截图,复现过程(修改文件,打包,运行,调试依次重复)问题花了挺多时间(前后花了一周),

为什么会有这个教程, 感觉能帮助挺多想试水docker的小伙伴,

所谓的"微服务"就是基于docker来实现的,保持容器功能的单一,方便维护测试

本来还想继续写基于docker-compose的版本,这样文章的篇幅就太长了...抽空再写一篇

docker-compose部署的书写很优雅,配置一目了然,而且可以做比较复杂的容器编排...

有人肯定会提到Kubernetes,这货很流行,有兴趣的可以去看看,一般都是做大厂运维才会用到这货

有不对之处亦或者改善的方案请及时留言,会及时修正和改善.感谢阅读~~~