3 minute read

自从上次看到有人用docker轻轻松松跨环境用命令行打包后就心痒痒要学过来

为什么用docker打包

因为有时候你需要在windows和linux和Mac上用同一句话/同一个shell打包而且不需要先下载各种环境嘛。
因为有事时候你就想打出来的包马上就能用。而不是要部署jenkins等服务。
你需要做简单的环境隔离。不像去文件里面替换文件。而环境变量可以统一管理.
而这一切只需要你简单的开始尝试用docker打包。

docker怎么打包的前置环境。

相应的svn/git/docker 等源代码工具。也可以不需要。只需要你有docker就行。

接下来我们用一个项目(ccos)来举例

docker怎么拉代码

docker git怎么拉代码

cd `dirname $0`/

export PROJECT="blog"
export PROJECT_PATH=`pwd`

export URL="git@github.com:xxx/xxxx.git"
mkdir -p  ${PROJECT_PATH}/${PROJECT}

alias git="docker run -ti --name  ${PROJECT}_PULL \ 
        --rm \
        -v ${PROJECT_PATH}/${PROJECT}:/git \
        -v $HOME/.ssh:/root/.ssh  \
        alpine/git"

git clone $URL

解释下。
我们alias git命令到docker git的镜像命令。
并且我们挂载了两个地址。一个是Home目录下的git配置地址。另一个是项目目录地址。
安全验证是通过-v进行HOME目录挂载。大家也可以挂载到指定目录。也可以用 git clone http://$account:$passwd@github.com/friddle/blog.git来绕过安全验证。

SVN拉去代码

同样脚本

cd `dirname $0`/

export PROJECT="blog"
export PROJECT_PATH=`pwd`

export URL="http://xxx/trunk/ccos"
mkdir -p  $PROJECT_PATH/$PROJECT

alias svn="docker run -ti --name  $(PROJECT)_PULL \ 
        --rm \
        -v $(PROJECT_PATH)/$(PROJECT):/git \
        -v $HOME/.subversion:/root/.subversion  \
        aneesv/svn-client"

svn co  $URL 

通过上一轮的介绍大家都知道怎么把git或者svn代码拷贝到本地。 那假如想要更新代码怎么做了。还是git/svn命令直接搞定

   git pull origin master
   svn update .

docker怎么编译

docker编译其实分为很多类型。前端类型。后端类型。还有各种奇怪的类型。我会把各种类型贴出来。
不过通用的还是配置相应的环境PROJECT PROJECT_PATH 并且挂载到相应的环境到目录。相信大家看过脚本就会一目了然

docker编译maven项目

cd `dirname $0`/
echo `pwd`

export PROJECT="Blog"
export VERSION=`date '+%y%m%d' `
export PROJECT_PATH=`pwd`

mkdir -p build/$PROJECT/target/
docker run -ti \
       --name ${PROJECT}_BUILD \
       --rm \
       -v $HOME/.m2:/root/.m2 \
       -v $PROJECT_PATH/$PROJECT:/Project/ \
       -v $PROJECT_PATH/build/$PROJECT/target:/Target/ \
       -v $PROJECT_PATH/build/$PROJECT/build_in_docker.sh:/root/build_in_docker.sh:rw \
       driv/docker-maven-java-oracle /bin/bash /root/build_in_docker.sh

我们很清晰的看到为了最多利用缓存加快数据。

  1. 我们挂载了系统目录/.m2/,这样就会重复利用m2目录下载的包
  2. 我们挂载了两个目录。一个是项目目录下新建了的build目录。做一些编译相关的目录。
  3. 我们同样挂载了启动脚本。build_in_docker.sh。这样可以在docker内做复杂的操作
  4. 那我们把build_in_docker.sh文件放到build目录。这里面也可以自己改。只要能找到就行

build_in_docker.sh

cd /Project/
mvn install
cp ccos-amdin/target/*jar /Target/ccos-admin.jar

这样启动这个脚本就可以直接build一个jar包出来

docker编译gradle项目

# 主流程一致跟maven一致
cd `dirname $0`/
echo `pwd`

export PROJECT="CCOS"
export VERSION=`date '+%Y%m%d' `
export PROJECT_PATH=`pwd`

mkdir build/$PROJECT/target/||true
docker run -ti \
       --name ${PROJECT}_BUILD \
       --rm \
       -v $HOME/.gradle:/root/.gradle \
       -v $PROJECT_PATH/$PROJECT:/Project \
       -v $PROJECT_PATH/build/$PROJECT/target:/Target \
       -v $PROJECT_PATH/build/$PROJECT/build_in_docker.sh:/root/build_in_docker.sh:rw \
       gradle:6.6.1-jdk8-hotspot /bin/bash /root/build_in_docker.sh
cd /Project/
gradle build
cp ccos-admin/target/ccos-admin-1.0.jar /Target/ccos-admin.jar ||true

前端编译脚本

cd `dirname $0`/
echo `pwd`

export PROJECT="WEB"
export VERSION=`date '+%Y%m%d' `
export PROJECT_PATH=`pwd`




docker run -ti \
       --name ${PROJECT}_BUILD \
       --rm \
       -e profile:${PROFILE} \
       -v $PROJECT_PATH/$PROJECT:/Project:rw \
       -v $PROJECT_PATH/build/$PROJECT/target:/Target:rw \
       -v $PROJECT_PATH/build/$PROJECT/build_in_docker.sh:/root/build_in_docker.sh:rw \
       -v $PROJECT_PATH/build/$PROJECT/tmp/node_modules:/Project/$PROJECT/node_modules:rw \
       -v $PROJECT_PATH/build/$PROJECT/tmp/npm:/root/.npm/:rw \
       -v $PROJECT_PATH/build/$PROJECT/config/npmrc:/root/.npmrc:rw \
       node:14-buster /bin/bash /root/build_in_docker.sh

因为缓存比较多。尤其是node_module这个万年黑洞。可以选择挂载到宿主机的临时目录上,每次编译都重新install一遍然后生成。也可以在shell里面进行控制。进行update

# 一些常见脚本可以用
npm set registry https://r.npm.taobao.org # 注册模块镜像
npm set disturl https://npm.taobao.org/dist # node-gyp 编译依赖的 node 源码镜像
npm set sass_binary_site https://npm.taobao.org/mirrors/node-sass # node-sass 二进制包镜像
npm set electron_mirror https://npm.taobao.org/mirrors/electron/ # electron 二进制包镜像
npm set puppeteer_download_host https://npm.taobao.org/mirrors # puppeteer 二进制包镜像
npm set chromedriver_cdnurl https://npm.taobao.org/mirrors/chromedriver # chromedriver 二进制包镜像
npm set operadriver_cdnurl https://npm.taobao.org/mirrors/operadriver # operadriver 二进制包镜像
npm set phantomjs_cdnurl https://npm.taobao.org/mirrors/phantomjs # phantomjs 二进制包镜像
npm set selenium_cdnurl https://npm.taobao.org/mirrors/selenium # selenium 二进制包镜像
npm set node_inspector_cdnurl https://npm.taobao.org/mirrors/node-inspector # node-inspector 二进制包镜像

cd /Project/
cnpm install
cnpm run build
cp -r build/ /Target/

由于经常因为网络问题。所以可以默认设置选择项为taobao减少下载时间 当然假如有用yarn的同学。可以设置这些参数

npm install -g yarn||true
npm install -g tyarn||true

# yarn se
yarn config set registry https://r.npm.taobao.org # 注册模块镜像
yarn config set disturl https://npm.taobao.org/dist # node-gyp 编译依赖的 node 源码镜像
yarn config set sass_binary_site https://npm.taobao.org/mirrors/node-sass # node-sass 二进制包镜像
yarn config set electron_mirror https://npm.taobao.org/mirrors/electron/ # electron 二进制包镜像
yarn config set puppeteer_download_host https://npm.taobao.org/mirrors # puppeteer 二进制包镜像
yarn config set chromedriver_cdnurl https://npm.taobao.org/mirrors/chromedriver # chromedriver 二进制包镜像
yarn config set operadriver_cdnurl https://npm.taobao.org/mirrors/operadriver # operadriver 二进制包镜像
yarn config set phantomjs_cdnurl https://npm.taobao.org/mirrors/phantomjs # phantomjs 二进制包镜像
yarn config set selenium_cdnurl https://npm.taobao.org/mirrors/selenium # selenium 二进制包镜像
yarn config set node_inspector_cdnurl https://npm.taobao.org/mirrors/node-inspector # node-inspector 二进制包镜像

cd /Project/
tyarn install
tyarn run build
cp -r build/ /Target/

electron项目编译脚本

和常规的npm编译脚本没啥特别大的区别。但是要注意

  1. 因为打包成win包是需要默认wine环境的。所以镜像要替换下.
  2. 因为会依赖到复杂的二进制包。上面的默认镜像设置一定要设置.

来看下shell


cd `dirname $0`/../../
echo `pwd`

export PROJECT="WEB"
export VERSION=`date '+%Y%m%d' `
export PROFILE="debug"
export PROJECT_PATH=`pwd`

if [ ! -d repo/Proto ];then
   echo "必须先同步proto"
   exit 1
fi

docker run -ti \
       --name ${PROJECT}_BUILD \
       --rm \
       --env ELECTRON_CACHE="/root/.cache/electron" \
       --env ELECTRON_BUILDER_CACHE="/root/.cache/electron-builder" \
       -v $PROJECT_PATH/$PROJECT:/Project:rw \
       -v $PROJECT_PATH/build/$PROJECT/target:/Target:rw \
       -v $PROJECT_PATH/build/$PROJECT/build_in_docker.sh:/root/build_in_docker.sh:rw \
       -v $PROJECT_PATH/build/$PROJECT/tmp/node_modules:/Project/qqbookjson/node_modules:rw \
       -v $PROJECT_PATH/build/$PROJECT/tmp/npm:/root/.npm/:rw \
       -v $PROJECT_PATH/build/$PROJECT/config/npmrc:/root/.npmrc:rw \
       -v $PROJECT_PATH/build/$PROJECT/tmp/cache:/root/.cache/:rw \
       electronuserland/builder:wine /bin/bash /root/build_in_docker.sh

build_in_docker脚本和npm相同

怎么生成docker镜像

springboot项目生成docker镜像

FROM openjdk:8u312-oraclelinux8
LABEL authors="friddle@qq.com"

VOLUME /tmp

USER root
ARG user=montents
ARG group=montents
ARG uid=1000
ARG gid=1000
ARG Jar="ccos-jar.jar"

RUN groupadd -g ${gid} ${group}
RUN useradd -u ${uid} -g ${group} -s /bin/sh -m ${user} 

RUN mkdir -p /home/montents/
RUN chown -R montents:montents /home/montents/

USER montents
COPY ./target/${Jar} /home/montents/montnets.jar
COPY ./config /home/montents/config

RUN mkdir -p /home/montents/logs
RUN chown -R montents:montents /home/montents/logs/

ENV MYSQL_HOST "mysql"
ENV MYSQL_USER "root"
ENV MYSQL_PASS "montnents"
ENV MYSQL_DB "xxx"

ENV REDIS_HOST "redis"
ENV REDIS_PASSWD ""
ENV REDIS_DB 1

ENV AUTH_TYPE "None"
ENV AUTH_PUB_KEY ""
ENV AUTH_PRIVATE_KEY ""

ENV Profile "debug"

ENV LOG_PATH "/home/monents/logs/"
ENV LOG_LEVEL "DEBUG"

# 这边要传递
EXPOSE 8001:8001
ENTRYPOINT [ "java","-jar", \
            "-Dspring.datasource.url=jdbc:mysql://${MYSQL_HOST}/${MYSQL_DB}?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=CONVERT_TO_NULL",\
            "-Dspring.datasource.username=${MYSQL_USER}", \
            "-Dspring.datasource.password=${MYSQL_PASS}", \
            "-Dspring.redis.host=${REDIS_HOST}", \
            "-Dspring.redis.password=${REDIS_PASSWD}", \
            "-Dspring.redis.database=${REDIS_DB}", \
            "-Dlog.path=${LOG_PATH}", \
            "-Dlog.level=${LOG_LEVEL}", \
            "-Dspring.activee.profile=${Profile}", \
            "/home/montnets/ccos.jar"]
```dockerfile
启动项目的时候可以通过配置env环境来实现不同的环境隔离 
这里可以选择配置文件  

### 制作镜像文件
`docker build --rm -t montents/ccos-admin:${VERSION} --build-arg Jar=ccos-admin.jar -f build/ build/$PROJECT/`

-f 指向相应dockerfilemulu
而后面的地址是打包的根目录地址

```shell
export VERSION=`date '+%Y%m%d' `
docker run -ti \
       --name Crm \
       --restart=always \
       --rm \
       -d \
       --env-file ./config/TestBuild.env \
       montents/ccos-admin:${VERSION} 

TESTBuild.env

MYSQL_HOST=xxxx
MYSQL_USER=friddle
MYSQL_PASS=xxxx
MYSQL_DB=ccos

REDIS_HOST=xxx
REDIS_PASSWD=xxxx
REDIS_DB=1

LOG_PATH=/home/monents/logs/
LOG_LEVEL=DEBUG


AUTH_TYPE=None
AUTH_PUB_KEY=""
AUTH_PRIVATE_KEY=""

Profile="debug"

docker环境安全注意点

这里要强调一点。跑的任何服务都请使用非root运行。有些项目使用这个是不对的

windows注意点

windows 因为shell目录格式和各种powershell地址路劲不兼容。强烈建议开启Wsl2.0后在docker设置支持wsl后端。在WSL中跑命令。这样会少一点问题

Updated: