Docker命令和Dockerfile构建
docker 使用推荐
- 容器在开发环境中构建,然后轻松提交到测试环境中,最终进入生产环境
- docker推荐单个容器只运行一个应用程序或进程,RPC服务的调用
Docker概念及常用命令
docker只有两个重要概念
镜像:镜像是基于 联合文件系统 的一种层式结构,它是一种文件系统。
容器:容器是基于镜像的执行环境,我们的进程就是在容器中运行。
docker中路径必须是绝对路径或者是当前目录下的文件
容器命令
查询
docker ps #查询当前正在运行容器
docker ps -a #查询所有容器
--format选项 可以进一步控制信息显示
容器具体参数和配置(很重要的修改位置)
/var/lib/docker目录存放着镜像,容器和容器的配置文件
/var/lib/docker/containers目录存放容器的配置文件
查询docker统计信息
docker stats 容器名
运行
docker运行命令是指创建容器并启动两个步骤,因此同个容器只能执行一次
docker run [option] 镜像 命令
[option]
- -i -t: 告诉容器提供交互式shell,命令为/bin/bash
-
-d: 守护进程,此时容器会在后台运行并不会把输出的结果 (STDOUT) 打印到宿主机上面(输出结果可以用
docker logs查看),它与容器是否长久运行无关,它执行完"命令"后会自动停止 - --name 名字:指定容器名字,具有唯一性,可作为id
- --restart = always 无论容器如何退出都会自动重启,--restart=on-failure:5 容器非正常退出重启,最多尝试重启5次
- -p 8080:80 容器中80端口绑定到宿主机的8080端口上
- -P 直接将Dockerfile中声明的EXPOSE容器端口随机分配一个宿主机端口
- -v 本地绝对目录:挂载点 方便多个容器共享代码,镜像内并不保存这些数据
- --net=网络名 指定新容器会在哪个网络中运行
- --volumes-from 容器名:把指定容器里面的所有卷加入新创建的容器,保证容器间共享同样的卷。
端口映射使用非常频繁,详情可看该文: 端口映射
如果想要修改已启动容器的端口,请打包成镜像然后重新端口映射
启动
docker start [option]容器名
[option]
docker没有很多的start 参数,因为容器的主要参数在创建时(run命令)已经设定,无法通过start去覆盖修改,得改容器配置文件。
- -i 是否以交互shell的形式启动
退出容器
不管容器是以守护进程还是交互Shell形式,一旦完成指定命令就会自动退出,因此才需要将进程设为前台运行(如nginx),/bin/bash是交互式shell,执行exit会使该进程结束,从而导致容器停止。
exit # 这样会使容器停止
ctrl+P+Q # 容器不会停止
对运行中容器启动新进程
docker exec[option] 容器名 命令
# docker exec -i -t 容器名 /bin/bash
# docker exec -d 容器名 前台命令
删除
docker rm -f 容器名 # 删除特定容器
docker rm 'sudo docker ps -a -q'# 删除所有容器
修改容器名字
docker rename 原容器名 新容器名
宿主机复制文件到容器
docker cp /opt/test/file.txt mycontainer:/opt/testnew/
docker cp mycontainer:/opt/testnew/file.txt /opt/test/ //容器复制到宿主机
镜像命令
镜像是层级文件系统,两个概念
层级:每个修改步骤都会从它的下一层复制到当层,方便按层拆开复用
写时复制:当创建容器时,docker会创建一个镜像栈(栈内都是只读层),栈顶添加一个读写层,每次需要修改文件都是从只读层复制到读写层,因此各个镜像之间是相互独立不受影响。
拉取镜像
docker pull 镜像名:tag标签
查询镜像
docker search 镜像名
删除镜像
dcoker rmi 镜像名 #整个镜像栈都会被删除
# 删除none标签的镜像,通常是打包过程中失败的过程镜像
docker rmi $(docker images | grep "^<none>" | awk "{print $3}")
构建镜像DockerFile
构建DockerFile的意义很重要,以指令的形式保证镜像具备可重复性,透明性和幂等性
自己试了一把之后,坑很多,以此记录:
- 必须要清楚你的基础镜像的操作系统是什么,有ubuntu,centos,airpline,debian。
- 这就需要去镜像中心看一下你这个基础镜像的DockerFile它是基于什么基础镜像上做的
- 尽量使用centos或者debian的,虽然大一些,但是系统网上教程多一些,少坑
- 可以借鉴镜像中心的DockerFile,模仿来写。但是不能全抄,因为它的DockerFile所用到的软件不一定是最新的了,版本问题你不一定能够正常下载。而它因为当时就构建了镜像所以不会出现问题。
- 安装软件建议用网上的教程安装,不建议复制镜像中心的镜像的DockerFile
- docker镜像由于层级联合文件系统,所以写DockerFile调试的过程中,优先把稳定的命令放在前面,以免浪费不必要的时间
指令:
# 参数
FROM ubuntu:14.04 # 指定一个存在的基础镜像
MAINTAINER James # 声明镜像作者
ENV REFRESHED_AT 2020-01-16 # 声明环境变量,可以通过修改此处时间刷新构建,避免使用缓存
RUN apt-get update && apt-get install -y nginx # 在当前镜像中运行指定命令
WORKDIR /opt/webapp/db # 切换当前目录
ENV RVM_PATH /home/rvm # 设置环境变量,会被持久保存到容器中,无法使用RUN source命令,只能通过ENV设置
CMD ["nginx","-g","daemon off"] # 容器启动时运行的命令,数组形式配置
ENTRYPOINT["sh","exec.sh"] # 由于容器启动时只能执行一条命令,可以将多条命令写成脚本运行
VOLUME ["/data"] # 创建挂载点,也叫作指定卷
COPY 构建目录下文件 镜像目录 # 拷贝文件进入镜像,不会解压
EXPOSE 80 # 指定容器内部公开端口(仍需要在run命令中配置端口映射 如-p 8080:80)
DockerFile中只能运行安装命令,运行命令必须是使用CMD或ENTRYPPOINT等创建容器后运行的
#!/bin/sh
echo hello
nohup bert-base-serving-start -model_dir /home/release/bertModel_release -bert_model_dir /home/release/bertModel_release -model_pb_dir /home/release/bertModel_release -mode CLASS -max_seq_len 64 -port 7006 -port_out 7007 >> /home/model.log 2>&1 &
# 要指明使用的python版本
nohup /opt/conda/envs/py36_env/bin/gunicorn -w 4 -b 0.0.0.0:5000 Server:app >> /home/server.log 2>&1 &
tail -f /dev/null
- sh文件无法使用cd,可以有替代的,但我还没弄懂。目前解决方案是docker中设置最后启动的工作目录
- sh文件权限不足,解决方案是DockerFile中增加["sh"]选项,或RUN chmod +x entrypoint.sh
- docker启动后后台运行该脚本,由于使用了nohup,所以脚本很快就运行完成,容器也随之停止,加入“tail -f /dev/null”可以保证脚本一直处于运行状态
启动运行
docker build -t court_extraction(镜像名) .(Dockerfile所在目录)
构建好镜像后,就可以启动容器
docker run -d -p 5050:5000 --name court court_extraction(可以是镜像id或镜像名)
Dockerfile汇总
安装python
FROM continuumio/anaconda3
- 不建议直接安装python,一个是python2,3版本切换问题,一个是pip的版本问题,还有一个就是python安装需要的系统库。
- 无脑就是上anaconda3多香
安装java
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl ca-certificates fontconfig locales \
&& echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen \
&& locale-gen en_US.UTF-8 \
&& rm -rf /var/lib/apt/lists/*
COPY ./release /home/release
RUN mkdir /usr/local/java
COPY ./jdk-8u241-linux-x64.tar.gz /usr/local/java
RUN tar -zxvf /usr/local/java/jdk-8u241-linux-x64.tar.gz -C /usr/local/java
ENV JAVA_HOME /usr/local/java/jdk1.8.0_241
ENV JRE_HOME=$JAVA_HOME/jre
ENV CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib
ENV PATH $JAVA_HOME/bin:$PATH
RUN java -version
- 切记装oracle jdk,不要装open jdk。因为很多软件都是基于oracle jdk做的,装open jdk很可能有坑!(别贪快)
安装pyhanlp
continuumio/anaconda3默认会安装latest版本,而且使用conda命令时也会莫名更新python版本,所以需要限制python版本
FROM continuumio/anaconda3
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl ca-certificates fontconfig locales \
&& echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen \
&& locale-gen en_US.UTF-8 \
&& rm -rf /var/lib/apt/lists/*
COPY ./release /home/release
RUN mkdir /usr/local/java
COPY ./jdk-8u241-linux-x64.tar.gz /usr/local/java
RUN tar -zxvf /usr/local/java/jdk-8u241-linux-x64.tar.gz -C /usr/local/java
ENV JAVA_HOME /usr/local/java/jdk1.8.0_241
ENV JRE_HOME=$JAVA_HOME/jre
ENV CLASSPATH=.:$JAVA_HOME/lib:$JRE_HOME/lib
ENV PATH $JAVA_HOME/bin:$PATH
RUN java -version
RUN conda create --name py36_env python=3.6
RUN conda init bash
SHELL ["conda", "run", "-n", "py36_env", "/bin/bash", "-c"]
RUN pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/
# pyhanlp
RUN conda install -y -c conda-forge jpype1==0.7.0
RUN pip install pyhanlp==0.1.63
RUN hanlp -v
COPY ./requirements.txt /home/release
RUN pip install -r /home/release/requirements.txt