虚拟化技术程序员Docker容器

使用Docker-compose构建容器

2017-06-30  本文已影响620人  anyesu

前言


docker常用指令详解一文中介绍过使用 docker run 命令配合各种复杂的选项完成对容器的构建和运行,但是这么长串的命令真的不是很好记也容易敲错。Docker Compose 是一个用来定义和运行复杂应用的 Docker 工具,以 yaml 格式的数据来保存容器配置,使用更简单的命令完成对容器的管理。此外 docker-compose.yml 还起到一个说明文档的作用, 一切配置在里面显得一目了然,就不用另外单独写部署文档了。

1. 安装 Docker Compose(官方文档)
# curl方式安装(推荐)
# 如果权限不够,先执行 sudo -i 切换到root帐号
curl -L https://get.daocloud.io/docker/compose/releases/download/1.14.0/docker-compose-`uname -s`-`uname -m` > /tmp/docker-compose
chmod +x /tmp/docker-compose
sudo mv /tmp/docker-compose /usr/local/bin/docker-compose

# pip方式安装(需要python,[pip安装方法]())
sudo pip install docker-compose
2. 卸载 Docker Compose
# 对于curl安装方式
sudo rm /usr/local/bin/docker-compose

# 对于pip安装方式
pip uninstall docker-compose

使用方法(参考)


docker-compose [选项] [子命令]
命令选项列表
选项 说明
-f 指定配置文件, 默认为 ./docker-compose.yml
-p 设置项目名, 默认为配置文件上级目录名
--verbose 输出详细信息
-H 指定docker服务器, 相当于 docker -H
子命令列表
子命令 说明
build 构建或重建服务依赖的镜像(配置文件指定build而不是image)
config 校验文件并显示解析后的配置
images 列出容器使用的镜像
events 监控服务下容器的事件
logs 显示容器的输出内容 相当于 docker logs
port 打印绑定的开放端口
ps 显示当前项目下的容器,加-p参数指定项目名 相当于 docker ps
help 命令帮助
pull 拉取服务用到的镜像 相当于 docker pull
up 项目下创建服务并启动容器,如果指定了项目名,其他操作也要带上项目名参数。容器名格式:[项目名]\_[服务名]\_[序号]
down 移除 up 命令创建的容器、网络、挂载点、镜像
pause 暂停服务下所的容器
unpause 恢复服务下所有暂停的容器
rm 删除服务下停止的容器
exec 在服务下启动的容器中运行命令 相当于 docker exec,
run 服务下创建并运行容器 相当于 docker run ,与 up 命令的区别在于端口要另外映射,且不受start/stop/restart/kill等命令影响,容器名格式:[项目名]\_[服务名]\_run\_[序号]
scale 设置服务的容器数目,多增少删
start 开启服务(up命令创建的所有容器) 相当于 docker start
stop 停止服务(up命令创建的所有容器) 相当于 docker stop
restart 重启服务(up命令创建的所有容器) 相当于 docker restart
kill 像服务发送信号(up命令创建的所有容器) 相当于 docker kill
docker-compose.yml 语法(参考进阶用法)

示例结构:

networks: {}
services:
  [service-name-1]:
    image: ...
    network_mode: bridge
    ports:
      \- 8080:8080/tcp
    ...
  ...
  [service-name-N]:
    image: ...
    network_mode: bridge
    ports:
      \- 8080:8080/tcp
    ...
# docker-compose语法版本
version: '2.1'
volumes: {}

一般只写第二层内容即可, 如果要指定语法版本则要从最外层开始写。

示例


以我去年写的一篇websocket文章中的项目作为示例

在当前目录下创建 docker-compose.yml

# tomcat版
demo-websocket-tomcat:
  # 指定用于构建镜像的Dockerfile路径, 值为字符串
  build: '.'
  # 设置容器用户名(镜像中已创建),默认root
  user: user_docker
  # 设置容器主机名
  hostname: docker-anyesu
  # 容器内root账户是否拥有宿主机root账户的所有权限 [参考](http://blog.csdn.net/halcyonbaby/article/details/43499409)
  privileged: false
  # always (当容器退出时docker自动重启它)
  # on-failure:10 (当容器非正常退出, 最多自动重启10次, 10之后不再重启)
  restart: always
  # 容器的网络连接类型,anyesu_net是创建的自定义网桥
  net: anyesu_net
  # 挂载点,设置与宿主机之间的路径映射
  volumes:
  - /usr/anyesu/docker/tomcat-logs:/usr/anyesu/tomcat/logs
  # :ro表示只读,默认为:rw
  #- /usr/anyesu/docker/tomcat-logs:/usr/anyesu/tomcat/logs:ro
  # 与宿主机之间的端口映射
  ports:
  - 8080:8080
  # 设置容器dns, 如果设置了net项则此项失效, 暂不清楚原因, 不过可以使用本地文件映射为容器的/etc/resolv.conf文件。
  dns: 8.8.8.8
  # 设置容器环境变量
  environment:
    JAVA_OPTS: -Djava.security.egd=file:/dev/./urandom

# nodejs版
demo-websocket-nodejs:
  # 使用镜像
  image: node:alpine
  privileged: false
  restart: always
  volumes:
  - /usr/anyesu/docker/websocket-master/Nodejs-Websocket:/usr/anyesu/node
  ports:
  - 3000:8080
  - 3002:3002
  # 覆盖容器启动后默认执行的命令
  command: sh -c "npm install ws@1.1.0 express -g && node /usr/anyesu/node/server.js"
  environment:
    NODE_PATH: /usr/local/lib/node_modules

再创建 Dockerfile 文件, 用于构建镜像

FROM alpine:latest
MAINTAINER anyesu

RUN echo -e "https://mirror.tuna.tsinghua.edu.cn/alpine/v3.4/main\n\
https://mirror.tuna.tsinghua.edu.cn/alpine/v3.4/community" > /etc/apk/repositories && \
    # 设置时区
    apk --update add ca-certificates && \
    apk add tzdata && \
    ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && \
    echo "Asia/Shanghai" > /etc/timezone && \
    # 安装jdk
    apk add openjdk7=7.121.2.6.8-r0 && \
    # 安装wget
    apk add wget=1.18-r1 && \
    tmp=/usr/anyesu/tmp && \
    mkdir -p $tmp && \
    cd /usr/anyesu && \
    # 下载tomcat
    wget http://mirrors.tuna.tsinghua.edu.cn/apache/tomcat/tomcat-7/v7.0.78/bin/apache-tomcat-7.0.78.tar.gz && \
    tar -zxvf apache-tomcat-7.0.78.tar.gz && \
    mv apache-tomcat-7.0.78 tomcat && \
    # 清空webapps下自带项目
    rm -r tomcat/webapps/* && \
    rm apache-tomcat-7.0.78.tar.gz && \
    cd $tmp && \
    # 下载websocket-demo源码
    wget https://github.com/anyesu/websocket/archive/master.zip && \
    unzip master.zip && \
    proj=$tmp/websocket-master/Tomcat-Websocket && \
    src=$proj/src && \
    tomcatBase=/usr/anyesu/tomcat && \
    classpath="$tomcatBase/lib/servlet-api.jar:$tomcatBase/lib/websocket-api.jar:$proj/WebRoot/WEB-INF/lib/fastjson-1.1.41.jar" && \
    output=$proj/WebRoot/WEB-INF/classes && \
    mkdir -p $output && \
    # 编译java代码
    /usr/lib/jvm/java-1.7-openjdk/bin/javac -sourcepath $src -classpath $classpath -d $output `find $src -name "*.java"` && \
    # 拷贝到tomcat
    mv $proj/WebRoot $tomcatBase/webapps/ROOT && \
    rm -rf $tmp && \
    apk del wget && \
    # 清除apk缓存
    rm -rf /var/cache/apk/* && \
    # 添加普通用户
    addgroup -S group_docker && adduser -S -G group_docker user_docker && \
    # 修改目录所有者
    chown user_docker:group_docker -R /usr/anyesu

# 设置环境变量
ENV JAVA_HOME /usr/lib/jvm/java-1.7-openjdk
ENV CATALINA_HOME /usr/anyesu/tomcat
ENV PATH $PATH:$JAVA_HOME/bin:$CATALINA_HOME/bin

# 暴露端口
EXPOSE 8080

# 启动命令(前台程序)
CMD ["catalina.sh", "run"]

接着就可以构建并运行了

# 创建一个名为anyesu_net、网段为172.18.0.0的网桥(docker默认创建的网段为172.17.0.0)
docker network create --subnet=172.18.0.0/16 anyesu_net

# 子命令 up 选项:
# -d 后台运行
# --build 重新构建依赖的镜像(如果docker-compose.yml中指定了build项的话)
# --force-recreate 重启容器, 即使配置和镜像都没有改变
wget https://github.com/anyesu/websocket/archive/master.zip
unzip master.zip
sed -i 's$8082$3002$' ./websocket-master/Nodejs-Websocket/server.js
sed -i 's$8082$3002$' ./websocket-master/Nodejs-Websocket/js/chat.js
sudo docker-compose up -d --build --force-recreate

之后就可以通过 ip:8080ip:3000 访问两个项目了(注意防火墙开放这两个端口哦)

说明:
  1. 环境和应用打包到一个镜像中作为一个整体
  2. 环境和应用独立,可以自由组合
  1. 配置文件中 build 参数内容指定 Dockerfile 路径, 貌似在高版本中可以是map类型
  2. build 操作需要使用 sudo 提权,否则会报一些奇怪的错误
遇到的坑:

之前一个原本启动只要10秒的小项目在容器中有时候重启要好几分钟甚至可能会一直起不来,在中找到下面一段日志

INFO: Deploying web application directory /usr/anyesu/tomcat/webapps/ROOT
Jun 10, 2017 3:03:28 PM org.apache.catalina.startup.TldConfig execute
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Jun 10, 2017 3:14:01 PM org.apache.catalina.util.SessionIdGeneratorBase createSecureRandom
INFO: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [624,301] milliseconds.
Jun 10, 2017 3:14:05 PM org.apache.catalina.startup.HostConfig deployDirectory
INFO: Deployment of web application directory /usr/fuyou/tomcat/webapps/ROOT has finished in 644,588 ms
Jun 10, 2017 3:14:05 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8080"]
Jun 10, 2017 3:14:05 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-bio-8009"]
Jun 10, 2017 3:14:05 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in 644776 ms

关键的一句就是: Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [624,301] milliseconds
这个步骤竟然用了10分钟!查了一下发现是docker容器下随机数与熵池策略有问题。
解决方法如下,个人更推荐第二种

系列文章


Docker 学习总结

Docker 常用指令详解

使用Dockerfile构建镜像

Docker Daemon连接方式详解

Docker下的网络模式


转载请注明出处:http://www.jianshu.com/p/ee8e7d2eb645

上一篇下一篇

猜你喜欢

热点阅读