docker 部署使用yapi(修护mock漏洞)

yapi 介绍

在这里插入图片描述

YApi 是高效、易用、功能强大的 api 管理平台,旨在为开发、产品、测试人员提供更优雅的接口管理服务。可以帮助开发者轻松创建、发布、维护
API,YApi 还为用户提供了优秀的交互体验,开发人员只需利用平台提供的接口数据写入工具以及简单的点击操作就可以实现接口的管理。

官方文档

准备Dockerfile

这里更新了 version 版本 为 1.9.3,原先的版本都存在 高级 mock 脚本侵入危险,官方新提交的v1.9.3版本新增了更安全的 safeify 沙箱来保护脚本执行安全。

FROM node:12-alpine as builder
WORKDIR /yapi
RUN apk add --no-cache wget python make
ENV VERSION=1.9.3
RUN wget https://github.com/YMFE/yapi/archive/v${VERSION}.zip
RUN unzip v${VERSION}.zip && mv yapi-${VERSION} vendors
RUN cd /yapi/vendors && cp config_example.json ../config.json && npm install --production --registry https://registry.npm.taobao.org

FROM node:12-alpine
ENV TZ="Asia/Shanghai"
WORKDIR /yapi/vendors
COPY wait-for-it.sh /
#后面需要 bash 解释器去执行脚本,apline镜像默认使用 /bin/sh,所以需要在这里安装一下
RUN chmod +x /wait-for-it.sh && apk add --no-cache bash
COPY --from=builder /yapi/vendors /yapi/vendors
EXPOSE 3000

准备 config.json

{
  "port": "3000",
  "adminAccount": "xxx",
  "timeout":120000,
  "closeRegister":true,
  "db": {
    "servername": "mongo",
    "DATABASE": "yapi",
    "port": 27017,
    "user": "yapi",
    "pass": "admin.yapi",
    "authSource": "admin"
  },
  "mail": {
      "enable": true,
      "host": "smtp.exmail.qq.com",
      "port": 465,
      "from": "xxx",
      "auth": {
          "user": "xxx",
          "pass": "xxx"
      }
  },
  "ldapLogin": {
      "enable": true,
      "server": "ldap://l-ldapt1.com",
      "baseDn": "CN=Admin,CN=Users,DC=test,DC=com",
      "bindPassword": "password123",
      "searchDn": "OU=UserContainer,DC=test,DC=com",
      "searchStandard": "mail",
      "emailPostfix": "@163.com",
      "emailKey": "mail",
      "usernameKey": "name"
   }
}

借鉴域官方文档,可以不用配置mail 和 ldap 功能

准备依赖可用性检查脚本

这里可是有着一个大坑,docker-compose 里面有依赖关系的话,大家肯定都会使用官方文档所说的 depends_on 来处理吧。
没错,反正我是用这个来处理的,我第一次安装部署可能是运气比较好吧,部署yapi没出什么问题,这几天要迁移yapi 服务。
迁移嘛,很简单的拉。不就是备份mongodb 数据库数据,目标服务器启动yapi服务和mongodb服务后导入数据,不就完事了吗。
也没错,就这几步操作,中途因为 depends_on 坑了我大半天时间,哎,都怪自己太菜了。
也不多哔哔了, depends_on 这个官方介绍的是解决容器的依赖、启动先后的问题,没错它是解决了这个启动先后的问题,但是还有一点,注意:自身服务不会等待 依赖服务「完全启动」之后才启动。
这就导致了我后面启动yapi,一遍报错mongodb Authentication failed ,一遍 初始化成功后,在起来又提示 mongodb Authentication failed 问题,我真的是脑壳疼啊。

后面发现是yapi没等mongodb 完全启动就启动去连接mongodb,连接不上还提示认证有问题,我他喵醉了,看这里的提示我一直以为我配置文件中的账号密码和mongodb设置的不一样呢。 刚开始想的解决方是,在执行初始化和启动前设置个 sleep n 秒,结构发现不太好,你咋知道mongodb预计多久完全启动呢.继续上网查询相关内容,最后找到这个wait-for-it

wait-for-it.sh 是一个纯 bash 脚本,它将等待主机和 TCP 端口的可用性。 它对于同步相互依赖的服务(例如链接的docker 容器)的启动很有用。 由于它是一个纯 bash 脚本,因此它没有任何外部依赖项。 这家伙,很有用。它会检查目标端口是否可用,不可用的话将会为目标端口 sleep n 秒,这里的时间由 wait-for-it.sh脚本判断,我使用的感觉挺好。

github地址: https://github.com/vishnubob/wait-for-it

wait-for-it.sh

#!/usr/bin/env bash
# Use this script to test if a given TCP host/port are available

WAITFORIT_cmdname=${0##*/}

echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }

usage()
{
    cat << USAGE >&2
Usage:
    $WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]
    -h HOST | --host=HOST       Host or IP under test
    -p PORT | --port=PORT       TCP port under test
                                Alternatively, you specify the host and port as host:port
    -s | --strict               Only execute subcommand if the test succeeds
    -q | --quiet                Don't output any status messages
    -t TIMEOUT | --timeout=TIMEOUT
                                Timeout in seconds, zero for no timeout
    -- COMMAND ARGS             Execute command with args after the test finishes
USAGE
    exit 1
}

wait_for()
{
    if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
        echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
    else
        echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout"
    fi
    WAITFORIT_start_ts=$(date +%s)
    while :
    do
        if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then
            nc -z $WAITFORIT_HOST $WAITFORIT_PORT
            WAITFORIT_result=$?
        else
            (echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1
            WAITFORIT_result=$?
        fi
        if [[ $WAITFORIT_result -eq 0 ]]; then
            WAITFORIT_end_ts=$(date +%s)
            echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds"
            break
        fi
        sleep 1
    done
    return $WAITFORIT_result
}

wait_for_wrapper()
{
    # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
    if [[ $WAITFORIT_QUIET -eq 1 ]]; then
        timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
    else
        timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
    fi
    WAITFORIT_PID=$!
    trap "kill -INT -$WAITFORIT_PID" INT
    wait $WAITFORIT_PID
    WAITFORIT_RESULT=$?
    if [[ $WAITFORIT_RESULT -ne 0 ]]; then
        echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
    fi
    return $WAITFORIT_RESULT
}

# process arguments
while [[ $# -gt 0 ]]
do
    case "$1" in
        *:* )
        WAITFORIT_hostport=(${1//:/ })
        WAITFORIT_HOST=${WAITFORIT_hostport[0]}
        WAITFORIT_PORT=${WAITFORIT_hostport[1]}
        shift 1
        ;;
        --child)
        WAITFORIT_CHILD=1
        shift 1
        ;;
        -q | --quiet)
        WAITFORIT_QUIET=1
        shift 1
        ;;
        -s | --strict)
        WAITFORIT_STRICT=1
        shift 1
        ;;
        -h)
        WAITFORIT_HOST="$2"
        if [[ $WAITFORIT_HOST == "" ]]; then break; fi
        shift 2
        ;;
        --host=*)
        WAITFORIT_HOST="${1#*=}"
        shift 1
        ;;
        -p)
        WAITFORIT_PORT="$2"
        if [[ $WAITFORIT_PORT == "" ]]; then break; fi
        shift 2
        ;;
        --port=*)
        WAITFORIT_PORT="${1#*=}"
        shift 1
        ;;
        -t)
        WAITFORIT_TIMEOUT="$2"
        if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi
        shift 2
        ;;
        --timeout=*)
        WAITFORIT_TIMEOUT="${1#*=}"
        shift 1
        ;;
        --)
        shift
        WAITFORIT_CLI=("$@")
        break
        ;;
        --help)
        usage
        ;;
        *)
        echoerr "Unknown argument: $1"
        usage
        ;;
    esac
done

if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then
    echoerr "Error: you need to provide a host and port to test."
    usage
fi

WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}
WAITFORIT_STRICT=${WAITFORIT_STRICT:-0}
WAITFORIT_CHILD=${WAITFORIT_CHILD:-0}
WAITFORIT_QUIET=${WAITFORIT_QUIET:-0}

# Check to see if timeout is from busybox?
WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)

WAITFORIT_BUSYTIMEFLAG=""
if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
    WAITFORIT_ISBUSY=1
    # Check if busybox timeout uses -t flag
    # (recent Alpine versions don't support -t anymore)
    if timeout &>/dev/stdout | grep -q -e '-t '; then
        WAITFORIT_BUSYTIMEFLAG="-t"
    fi
else
    WAITFORIT_ISBUSY=0
fi

if [[ $WAITFORIT_CHILD -gt 0 ]]; then
    wait_for
    WAITFORIT_RESULT=$?
    exit $WAITFORIT_RESULT
else
    if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
        wait_for_wrapper
        WAITFORIT_RESULT=$?
    else
        wait_for
        WAITFORIT_RESULT=$?
    fi
fi

if [[ $WAITFORIT_CLI != "" ]]; then
    if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then
        echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess"
        exit $WAITFORIT_RESULT
    fi
    exec "${WAITFORIT_CLI[@]}"
else
    exit $WAITFORIT_RESULT
fi

安装docker-compose

compose官方文档:https://docs.docker.com/compose/install/#install-compose

Daocloud 容器云平台帮助下载

curl -L https://get.daocloud.io/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

编写docker-compose.yaml

准备工作完成,编写docker-compose.yaml

version: '2.1'
services:
  mongodb:
    image: mongo:latest
    container_name: mongo
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: yapi
      MONGO_INITDB_ROOT_PASSWORD: admin.yapi
      MONGO_INITDB_DATABASE: yapi
    volumes: 
      - "./mongo/data:/data/db"
    networks: 
      my-yapi: 
        ipv4_address: 192.168.10.2
  yapi:
    build:
      context: ./
      dockerfile: Dockerfile
    image: yapi
    container_name: yapi
    #第一次初始化
    command: "bash /wait-for-it.sh mongodb:27017 -- /usr/local/bin/npm run install-server"
    #之后使用下面的命令
    # command: "bash /wait-for-it.sh mongodb:27017 -- node /yapi/vendors/server/app.js"
    ports: 
      - 3000:3000
    depends_on:
      - mongodb
    volumes: 
      - "./config.json:/yapi/config.json"
    networks:
      my-yapi: 
        ipv4_address: 192.168.10.3

networks:
  my-yapi:
    driver: bridge
    ipam:
      config:
        - subnet: 192.168.10.0/24

启动示范

#启动时会自动编译镜像,没有加 -d 后台运行是因为 yapi 需要初始化
docker-compose  up
#初始化完毕后,注释掉yaml里的 run install-server 这句,取消下面的command 注释
#yapi的初始化只需要执行一遍,它就是将需要的结构数据写入mongodb,mongodb数据持久化后,后面都不在需要执行初始化命令
docker-compose up -d  #这次执行会更新为启动命令,不再是初始化命令

参考文章: https://www.jianshu.com/p/a97d2efb23c5

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值