资讯专栏INFORMATION COLUMN

定制自己的应用镜像

cnio / 2301人阅读

摘要:指定了自己的执行器,还有其他的写法注意我们在取镜像名的时候,这里要注意,字母只能全部小写。

这部分介绍比较实用,在开中会经常用到,因为我们会根据自己的项目来构建自己的镜像,然后发布。

第一种定制方式

首先跑起来一个ubuntu,在ubuntu上安装相应的软件。

docker run -it --name temp ubuntu /bin/bash

进来后,安装一个apache2吧

apt-get update && apt-get install apache2

使用dpkg -L来查看下apache2安装的位置。在/usr/local/apache2就是我们安装的。

开始以这个容器为基础来制作镜像吧!

docker commit -a "robinyang" temp robinyang0909/apache2:latest

好了,很快就会出现长uuid说明生成完成了。执行docker ps看看

你肯定有疑惑,开发要是这样来为应用制作镜像的话,岂不是要疯了,确实,我也这么觉得,死难用!别慌,下面来看看第二种制作镜像的方法。

第二种定制方式

首先,在学习目录下新建一个buildImage下新建一个Dockerfile文件(buildImage是一个docker上下文)。并在新建文件里加入下面指令:

FROM ubuntu:14.04
MAINTAINER robinyang
RUN apt-get update && apt-get install nginx
RUN echo "HelloWorld">/usr/share/nginx/html/index.html
EXPOSR 80

保存退出,先来执行下:

docker build -t robinyang0909/nginx:latest .

上面指定不知道什么意思吗?第一节有操作过,当然,记不住啊!确实有时候忘记了,docker build --help 查看。

这里说下原理,每执行一条指令都穿创建一个镜像层,并且会commit提交,执行吓一跳指定,就是基于刚才的镜像层来创建。

你会发现在你的镜像列表里多出一个你刚才构建的镜像。这样的好,我们可以在我们的项目的顶级目录下新建一个Dockerfile来给你的应用定制镜像。既然用Dockerfile来构建镜像的话,我们先来系统了解一下Dockerfile所需要的基本指令。

Dockerfile 基本参数 FROM

Dockerfile的第一条指令,后面指定一个基础镜像。你新建的镜像是想基于那个基础镜像来构建的。一定要放在第一句。

FROM ubuntu:14.04

你可以 docker search 去搜索你需要的镜像。

MAINTAINER

指定这个镜像的作者信息。

MAINTAINER robinyang robinyang_beijing@163.com
RUN

这个用的很多,就详细说说。在构建镜像的时候,在当前镜像层里执行这些shell脚本,并且会commit,构建成新一层镜像。

RUN    //默认是使用/bin/sh 来执行

RUN ["", "", "", ...]    //默认调用docker exec来执行,有的镜像没有sh

来看几个例子

RUN touch /tmp/hello.html && echo hello>hello.html

RUN /bin/bash -c "touch /tmp/hello.html && echo hello>hello.html"

RUN ["/bin/bash", "-c", "touch /tmp/hello.html && echo hello>hello.html"]

RUN ["touch", "/tmp/hello.html && echo hello>hello.html"]
EXPOSE

这个很简单,让你的容器在运行的时候监听哪个端口。但是有一点要注意,他监听的是容器的端口,而不是主机的端口,所以我们创建容器的时候,要用 -p 来指定端口。

EXPOSE 8080

学了以上的几个命令的话,现在可以来个小练习。以tomcat为基础,加入一个hello.html页面,并在页面中加入一个helloWorld内容。

FROM tomcat
MAINTAINER robinyang robinyang_beijing@163.com

RUN touch /usr/local/tomcat/webapps/ROOT/hello.html
RUN ["/bin/bash", "-c", "echo helloWorld>/usr/local/tomcat/webapps/ROOT/hello.html"]

EXPOSE 8080

构建下

docker build -t robinyang09090/tomcat:latest .

镜像制作完成了,现在可以创建容器了

docker run -d -p 8080:8080 --name testTomcat robinyang09090/tomcat

【-p 宿主机:容器】

可以用你的浏览器访问下 host:8080/hello.html试试。

ENV

在上面的Dockerfile 构建文件中,我们会发现很多有重复的,可以用一个变量来带代替重复的地方。改写下上面Dockerfile

FROM tomcat
MAINTAINER robinyang robinyang_beijing@163.com

ENV rootPath=/usr/local/tomcat/webapps/ROOT/hello.html

RUN touch $rootPath
RUN ["/bin/bash", "-c", "echo helloWorld>$rootPath"]

EXPOSE 8080

是不是简洁很多。这里ENV的书写有两种方式:

ENV key1=val1 key2=val2  //推荐
或者
ENV key1 val1
ENV key2 val2

这些变量会被持久保存到我们创建的任何容器里,所以我们取的变量名要注意,别和系统自带变量名冲突就行。

CMD

在容器启动的时候执行的命令,RUN则是在构建镜像的时候执行的命令,这里要区分开。还记得我们在之前容器里执行循环,docker run后面 /bin/sh -c "while [ true ]; do echo helloWorld; sleep 1; done"相当于CMD的作用。

FROM ubuntu
    
CMD ["/bin/sh", "-c", "while [ true ];do echo helloWorld; sleep 1;"] 
//指定了自己的执行器, CMD ["executable","param1","param2"]

//还有其他的写法
CMD ["param1","param2"] (as default parameters to ENTRYPOINT)
CMD command param1 param2 (shell form)

注意:我们在docker build -t 取镜像名的时候,这里要注意,字母只能全部小写。给容器取名的可以大写。

可以构建我们的镜像了

docker build -t robinyang0909/loop .

创建并运行容器

docker run -d --name testLoop robinyang0909/loop

//接着打印日志
docker logs testLoop 
ENTRYPOINT

这个指令跟CMD有点类似,都是容器启动成功开始运行执行脚本;但又不同的地方,CMD会被覆盖,而ENTRYPOINT不会被覆盖;ENTRYPOINT是一个基础前缀指令。

ENTRYPOINT ["/bin/sh", "-c"]
CMD ["java Hello"]

上面的会构成一个完整的指令/bin/sh -c java Hello,CMD或者docker run后面的参数,都会传入ENTRYPOINT,他来指定执行器,我们这里的执行器是/bin/bash -c,一般我们会ENTRYPOINT和CMD搭配起来一起用。

WORKDIR

上面ENTRYPOINT里我们指定了一个java Hello运行我们自己的jar包,但是有一个问题,你怎么知道你的jar在哪里。就算你知道目录了,你难道要在Hello前拼接路径吗?这样确实可以,但是不优雅,这里有更好的方法,就是WORKDIR。

WORKDIR指定一个工作目录,这样CMD和ENTRYPOINT就会在该目录下执行我们的程序。

FROM java
ENV jarPath=/var/class/
ENTRYPOINT ["/bin/sh", "-c"]
WORKDIR $jarPath

CMD ["java Hello"]

构建镜像后,run一个容器,启动会失败!别慌,还有一步没有完成,等下一步完成后,就可以了。

WORKDIR可以多次出现,意思就是切换目录。

COPY

上面的例子跑不起来,还缺少COPY一个Hello文件,接下来,将会拷贝一个文件到镜像里去。在Dockerfile同级目录下新建一个tmp文件,生成一个Hello.class文件。

COPY tmp/Hello.class /var/class/

补充上面的,完整的是

FROM java
ENV jarPath=/var/class/
ENTRYPOINT ["/bin/sh", "-c"]
WORKDIR $jarPath

COPY tmp/Hello.class $jarPath
CMD ["java Hello"]

生成镜像docker build -t roinyang0909/hello . ,创建启动容器docker run -d --name hello robinyang0909/hello,看下容器的日志docker logs hello发现我们的java程序跑起来了。

上面的 CMD ["java Hello"]千万别写成了CMD ["java", "Hello"]系统会先执行java再执行Hello的,是分步执行的,很显然只运行java指令就出错。建议 一个 ""就引起一个完整的指令。

上面COPY文件的时候,我们只能拷贝上下文里的文件,上下文之外的文件是没法拷贝成功的。什么是上下文了,就是Dockerfile文件所在目录及其子目录,都是上下文。

VOLUMN

这个指令,估计有点陌生,确实!首先我们来谈谈容器的存储机制,我们知道,容器只能在最上面的读写层进行文件的读写,这样做理论上没有问题,但是你有没有想过一个很严重的问题,我在这个容器里写了一些东西,下次升级,旧容器里的文件是不是要拷贝出来,然后放入到新容器里去,最典型的应用就是数据库容器。现在我们可以将宿主机的一个目录挂在到容器上,这样可以将数据放到宿主机上。

来吧!我们用容器跑一个mysql

docker pull mysql   //拉去mysql镜像

docker run -d -p 3307:3306 --name mysql1 -e MYSQL_ROOT_PASSWORD=root mysql  //创建启动mysql容器

用SQLyog工具连接3307,密码为root ,没有问题。我们创建一个demo库。docker stop mysql1关闭容器,重新创建启动一个mysql2的容器docker run -d -p 3307:3306 --name mysql1 -e MYSQL_ROOT_PASSWORD=root mysql,再次连接,发现我们刚才创建的demo库没有了。然后你可能想到的解释就是,mysql容器将数据放在了容器里面,不同的容器数据当然不一样。这样理解,也不能算错。其实数据是写在宿主机上的,因为mysql这个镜像指定了VOLUMN,https://github.com/docker-lib... 这是docker镜像的制作github仓库,在Dockerfile 里可以看到VOLUME /var/lib/mysql已经挂在了/var/lib/mysql。

其实Dockerfile的VOLUMN挂在,只是挂在了/var/lib/docker/volumes/w75wew.../_date/这个下面的一个零食目录里的,可以docker inspect mysql1看到Mounts信息,挂在在Source指定的宿主机目录下

name的一长串数字字符组成的id是唯一的,每次启动一个Dockerfile指定了VOLUMN的容器,都会创建一个像这样的目录,所以新建容器就是一个新的,是没有数据的。

容器删除的时候,这些零时文件不会被删除的。假设我们没有将这些目录挂在到宿主机上,容器删除了,数据还在。只不过寻找过程麻烦点,但是这也会是一个补救的机会。

小结: 在Dockerfile里指定VOLUMN会映射到宿主机上,但是他会在/var/lib/docker/volumns/下生成一个唯一的目录来做挂载。

能不能让容器的挂在目录映射到我指定的目录下?当然能

docker run -d -p 3307:3306 --name mysql2 -e MYSQL_ROOT_PASSWORD=root -v /home/mysql/data/:/var/lib/mysql mysql   //将容器的/var/lib/mysql映射到宿主机的/home/mysql/data/

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/26907.html

相关文章

  • 构建与定制:唯品会 PaaS 基于 Kubernetes 实践

    摘要:基于年底或年初没有推广的现状,唯品会部门目前已经做了两年的时间。唯品会现状唯品会目前线上有一千多个域,每个域之间相互的依赖比较复杂,每次的部署发布困难。这是唯品会的架构,主要包含持续集成和持续部署。 数人云上海&深圳两地容器之Mesos/K8S/Swarm三国演义的嘉宾精彩实录第三更来啦。唯品会是数人云Meetup的老朋友,去年曾做过RPC服务框架和Mesos容器化的分享。本次分享中,...

    JackJiang 评论0 收藏0
  • 从零开始学习 Docker

    摘要:此命令下载测试镜像并在容器中运行它。国内很多云服务商都提供了加速器服务,例如阿里云加速器注册用户并且申请加速器,会获得如这样的地址。获取镜像阿里云镜像库上有大量的高质量的镜像可以用,这里我们就说一下怎么获取这些镜像并运行。 showImg(https://segmentfault.com/img/remote/1460000012924583); 这篇文章是我学习 Docker 的记录...

    lily_wang 评论0 收藏0
  • 如何用Docker定制自己Beego环境

    摘要:如何用定制你自己的环境前言学习几个月了,一直在论坛和群里潜水,一直都想写点什么回报大家积极的知识分享。关于如何使用,可以参考上面的文章和官方文档二小试牛刀,用构建一个的环境并运行程序首先来贴上我的先附上这个项目地址。 如何用Docker定制你自己的Beego环境 前言: 学习golang几个月了,一直在论坛和qq群里潜水,一直都想写点什么回报大家积极的知识分享。 前几日在CSDN上...

    alaege 评论0 收藏0
  • Docker学习之基本概念及安装(1)

    摘要:分层存储因为镜像包含操作系统完整的文件系统,其体积往往是庞大的,因此在设计时,就充分利用的技术,将其设计为分层存储的架构。分层存储的特征还使得镜像的复用定制变的更为容易。 什么是Docker Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源。Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级、可移植的容器中,然后发布到任何流行的 L...

    lvzishen 评论0 收藏0
  • Dockerfile 与 Compose 环境搭建学习笔记(一)

    摘要:的主要作用是自己根据基础镜像,重新定制镜像,而不是直接从官方仓库拿现成的使用。以接下来要构建的环境来说明下,下面我将要搭建一个的开发环境,需要进行配合。它的主要作用是持久化数据,避免容器销毁后内部数据丢失暴露到宿主机的端口。 以前一直使用 Vagrant 作为自己的开发环境,并且在上家公司也推行大家采用 Vagrant 作为开发环境,保障公司使用的是同一套开发环境。随着docker的流...

    TZLLOG 评论0 收藏0

发表评论

0条评论

cnio

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<