前文中,罗列了docker使用中用到的基本命令

此文,将会对怎样使用Dockerfile去创建一个镜像做简单的介绍

Dockerfile命令

要开始编写Dockerfile,首先要对相关的命令有个清晰的认识

下面列出了部分Dockerfile命令的功能以及使用方法,供参考:

1. FROM

Dockerfile的第一条指定必须是FROM,用于指定基础镜像。

用法:

FROM [image]:[tag]

2. MAINTAINER

用于指定此Dockerfile维护者信息。

用法:

MAINTAINER <name> <email>

3. ADD

复制指定内容到镜像中,指定内容可以是一个相对或绝对路径,也可以是一个url(此时相当于wget),如果添加的文件是个tar压缩文件,文件在复制的时候会自动解压。

用法:

ADD <src> <dest>

4. COPY

与ADD命令用法相同,区别是COPY只能复制本地文件

用法:

COPY <src> <dest>

5. RUN

构建镜像时运行指定命令,建议多个命令尽量写在同一个RUN中,用&&分割或使用\换行。

用法:

RUN <command>

RUN ["executable", "param1", "param2"]

前者在shell终端上运行,后者使用exec运行。

6. CMD

容器启动时运行指定命令,每个容器只能执行一条CMD命令,多个CMD命令时,只最后一条被执行。

用法:

CMD ["executable","param1","param2"]

CMD ["param1","param2"]

CMD <command> <param1> <param2>

7. ENV

指定一个环境变量,可以被RUN,WORKDIR命令使用,并在容器运行时保持。

用法:

ENV <key> <value>

ENV <key1>=<value1> <k2>=<v2> <k3>=<v3> ...

8. ENTRYPOINT

配置容器启动后执行的命令,并且不可被 docker run 提供的参数覆盖,每个Dockerfile中只能有一个 ENTRYPOINT ,当指定多个时,只有最后一个起效。

用法:

ENTRYPOINT [“executable”, “param1”, “param2”]

ENTRYPOINT <command> <param1> <param2>

9. WORKDIR

设置工作目录,对RUN,CMD,ENTRYPOINT,COPY,ADD生效。如果不存在则会创建。

用法:

WORKDIR <path>

10. EXPOSE

功能为暴漏容器运行时的监听端口给外部

用法:

EXPOSE <port>

Dockerfile实践

通读过上面的Dockerfile命令,相信对编写一个Dockerfile有了一个初步的认识

接着,我们来通过一个具体的需求,来看一个完整的镜像是怎么通过Dockerfile生成的

1. 需求

使用32位的jre环境运行一个dubbo服务的jar包

2. 编写Dockerfile

首先,我们需要一个32位的jre环境,你可以从镜像仓库找一个,但此处,我们选择通过Dockerfile自己创建

# 指定基础镜像
FROM i386/centos:6
# 作者信息
MAINTAINER trainoo "trainoo@163.com"
# 添加jre环境,add会自动解压
ADD jre-8u211-linux-i586.tar.gz /opt/docker/java/jre8
# 设置java环境变量
ENV JAVA_HOME=/opt/docker/java/jre8/jre1.8.0_211 \
CLASSPATH=$JAVA_HOME/bin \
PATH=.:$JAVA_HOME/bin:$PATH
# 容器启动后执行,显示java版本号,可以查看环境是否安装成功
CMD ["java","-version"]

问:为什么使用 i386/centos:6 作为基础镜像?

答:因为32位的jre当然是使用32位的环境运行比较方便

如果使用64位的环境运行32位jre也是可以的,但是需要安装如下依赖:

RUN yum update && yum -y install glibc.i686 zlib.i686 libstdc++.i686

如果打包的是64位的jre,那么基础镜像可以换成:frolvlad/alpine-glibc

问:jre-8u211-linux-i586.tar.gz 这个包从哪下载?

答:你可以从官网下载,当然,你看到此文章时,可能网址已经变化。

3. 构建

如上,我们写好了一个Dockerfile,只需把jre包跟Dockerfile放在同一路径

即可开始构建,命令如下:docker build -t jre8-64:second .

ps: 此处应该贴32位的运行过程的,但是64位的跟32位没太大区别,所以就这样吧

[root@xxx jre8-x32]# ll
total 89060
-rw-r--r--. 1 root root 369 Jun 27 18:38 Dockerfile
-rw-r--r--. 1 root root 91192891 Jun 26 14:52 jre-8u211-linux-i586.tar.gz [root@xxx jre8-x64]# docker build -t jre8-64:second .
Sending build context to Docker daemon 87.86MB
Step 1/5 : FROM frolvlad/alpine-glibc:alpine-3.10
---> 74b43ef19206
Step 2/5 : MAINTAINER trainoo "trainoo@163.com"
---> Using cache
---> 1257f5f17f2a
Step 3/5 : ADD jre-8u211-linux-x64.tar.gz /opt/docker/java/jre8
---> Using cache
---> 10692b79be49
Step 4/5 : ENV JAVA_HOME=/opt/docker/java/jre8/jre1.8.0_211 CLASSPATH=$JAVA_HOME/bin PATH=.:$JAVA_HOME/bin:$PATH
---> Running in 1710cc8fd3aa
Removing intermediate container 1710cc8fd3aa
---> 5dd2f0ae922c
Step 5/5 : CMD ["java","-version"]
---> Running in 368238c0940b
Removing intermediate container 368238c0940b
---> e6e9cf729e37
Successfully built e6e9cf729e37
Successfully tagged jre8-64:second [root@xxx jre8-x64]# docker images -f reference=jre8*
REPOSITORY TAG IMAGE ID CREATED SIZE
jre8-64 second e6e9cf729e37 53 seconds ago 251MB
jre8-32 base 9035f0dcd0ed 20 hours ago 433MB
jre8-64 base ce0823b7fdc3 47 hours ago 251MB

由上面的构建步骤可以看出,每运行一个命令,都会产生一个临时镜像,所以为了避免产生多余的临时镜像,我们要尽量的把多个相同指令的的构建步骤,写在同一行里。

4. 运行项目

假设我们把项目打包好了,打包好的jar包为:my-service-1.0.jar。

FROM jre8-32:base
MAINTAINER trainoo "trainoo@163.com"
COPY ./jar/ /opt/dubbo-server/
RUN cd /opt/dubbo-server/ && mv $(ls | grep jar) app.jar
WORKDIR /opt/dubbo-server/
CMD ["java","-Xms512M","-Xmx512M","-jar","app.jar"] // 为了通用性,这里把jar文件(如果不是springboot项目,还有lib等依赖包)放在jar目录下,COPY时一起复制过去
// 同样目的,使用 mv $(ls | grep jar) app.jar 将需要被执行的jar文件统一命名成 app.jar
# 构建镜像
[root@xxx jre8-x64]# docker build -t myservice:v1 .
.....此处省略部分.....
# 启动容器
[root@xxx jre8-x64]# docker run -d --name myservice myservice:v1
# 查看容器
[root@xxx jre8-x64]# docker ps

后续总结

事情总是不会这么顺利,中途总是会有一些小插曲,所以下面是可能遇到的问题的解决方案

docker 批量删除产生的缓存镜像
# 第一种风格
docker ps -a | grep "Exited" | awk '{print $1 }'|xargs docker stop
docker ps -a | grep "Exited" | awk '{print $1 }'|xargs docker rm
docker images | grep none | awk '{print $3}' | xargs docker rmi # 第二种风格
docker rm $(docker ps -aq -f status=exited)
docker rmi $(docker images -qa -f reference=*:v1)
container 时区跟 host 不一致
# Dockerfile中添加
RUN echo "Asia/Shanghai" > /etc/timezone # 启动时添加:-v /etc/localtime:/etc/localtime:ro
docker run -d -v /etc/localtime:/etc/localtime:ro --net mynet --name myservice myservice:v1
docker运行项目,日志中文显示???
# Dockerfile中添加,指定语言环境
RUN localedef -i en_US -f UTF-8 en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8

Dockerfile极简入门与实践的更多相关文章

  1. Git 极简入门教程学习笔记

    Git 极简入门教程  http://rogerdudler.github.io/git-guide/index.zh.html 测试用 https://github.com/xxx/BrnShop. ...

  2. .Net Core in Docker极简入门(下篇)

    Tips:本篇已加入系列文章阅读目录,可点击查看更多相关文章. 目录 前言 开始 Docker-Compose 代码修改 yml file up & down 镜像仓库 最后 前言 上一篇[. ...

  3. ElasticSearch极简入门总结

    一,目录 安装es 项目添加maven依赖 es客户端组件注入到spring容器中 es与mysql表结构对比 索引的删除创建 文档的crud es能快速搜索的核心-倒排索引 基于倒排索引的精确搜索. ...

  4. Spring Security极简入门三部曲(上篇)

    目录 Spring Security极简入门三部曲(上篇) 写在前面 为什么要用Spring Security 数据库设计 demo时刻 核心代码讲解 小结 Spring Security极简入门三部 ...

  5. Spring Security极简入门三部曲(中篇)

    目录 Spring Security极简入门三部曲(中篇) 验证流程 Authentication接口 过滤器链 AuthenticationProvider接口: demo时刻 代码讲解 小结 Sp ...

  6. Express + Mongoose 极简入门

    今天尝试使用express + mongoose,构建了一个简单的Hello world,实现以下功能: 定义mongodb使用的Schema,一个User 访问/输出Hello world 访问/i ...

  7. .Net Core in Docker极简入门(上篇)

    目录 前言 开始 环境准备 Docker基础概念 Docker基础命令 Docker命令实践 构建Docker镜像 Dockerfile bulid & run 前言 Docker 是一个开源 ...

  8. Svelte 极简入门

    ​弹指之间即可完成.   注意:原文发表于 2017-8-7,随着框架不断演进,部分内容可能已不适用.     Svelte 是一种新型框架.   以往我们要引入一个框架或者类库,可以通过在页面上放置 ...

  9. Spring Boot 如何极简入门?

    Spring Boot已成为当今最流行的微服务开发框架,本文是如何使用Spring Boot快速开始Web微服务开发的指南,我们将创建一个可运行的包含内嵌Web容器(默认使用的是Tomcat)的可运行 ...

随机推荐

  1. 从HTML标签开始

    开始这一切吧! 没错,你没看错,我将从HTML标签开始我的整个系列文章.很基础吧?但是每个前端人都是从最简单的HTML标签开始的,都是从一个<html></html>开始整个前 ...

  2. JS面试准备二

    1.常用的字符串方法 1. indexOf:查找字符串某一项的初始位置2. slice:截取字符串(包含起始位置,不包含结束位置) 不会根据参数大小,交换参数位置 如果出现-1按倒数第一个数,如果出现 ...

  3. [LeetCode] 1370. Increasing Decreasing String

    1. 原题链接:https://leetcode.com/problems/increasing-decreasing-string/ 2. 解题思路 直观的想法是:用有序map<char, i ...

  4. call 和 apply 和 bind的区别

    有些东西说忘就往,每天记录自己忘记的东西重新学习一遍,挺好 作用:call()和apply()用法都是一样的,改变this的指向问题 区别:接收参数的方式不同, (bind 方法是附加在函数调用后面使 ...

  5. Java基础 - Date的相关使用(获取系统当前时间)

    前言: 在日常Java开发中,常常会使用到Date的相关操作,如:获取当前系统时间.获取当前时间戳.时间戳按指定格式转换成时间等.以前用到的时候,大部分是去网上找,但事后又很快忘记.现为方便自己今后查 ...

  6. LoadRunner初入门(安装)

    在经过了两天网上找软件-真机上装软件-完了发现真机不能用(不能用的原因就是IE不能打开 试了很多方法现在真机上的ie变成了ie8英文版),果断用上了虚拟机 虚拟机刚开始要装镜像 一开始下的是64位的发 ...

  7. pytest、tox、Jenkins实现python接口自动化持续集成

    pytest介绍 pytest是一款强大的python测试工具,可以胜任各种级别的软件测试工作,可以自动查找测试用并执行,并且有丰富的基础库,可以大幅度提高用户编写测试用例的效率,具备可扩展性,用户自 ...

  8. Leetcode 1160: 拼写单词

    给你一份『词汇表』(字符串数组) words 和一张『字母表』(字符串) chars. 假如你可以用 chars 中的『字母』(字符)拼写出 words 中的某个『单词』(字符串),那么我们就认为你掌 ...

  9. 记一次:Windows的Socket编程学习和分析过程

    Socket编程依赖于:WS2_32.dll --- 服务端 --- .导入我们需要的函数 #incldue <windows.h> //#include<WinSock2.h> ...

  10. [Java网络安全系列面试题]常见web攻击有哪些?

    搞Web开发离不开安全这个话题,确保网站或者网页应用的安全性,是每个开发人员都应该了解的事.本篇主要简单介绍在Web领域几种常见的攻击手段及Java Web中的预防方式. 1. XSS 1.1 什么是 ...