Docker教程-9-构建镜像并上传到DockerHub仓库

Posted 孔子-说

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Docker教程-9-构建镜像并上传到DockerHub仓库相关的知识,希望对你有一定的参考价值。

转自Docker教程-9-构建镜像并上传到DockerHub仓库,更优体验http://www.kongzid.com/

目录

1、基于已有镜像构建镜像并上传到DockerHub

1.1更改已安装的镜像容器

1.2 基于上述容器重新创建镜像

1.3 上传镜像到DockerHub仓库

2、使用Dockerfile构建JDK+tomcat镜像

2.1 准备好jdk和tomcat安装包等文件

2.2 编写Dockerfile文件

2.3 设置Dockerfile权限

2.4 执行 docker build 构建镜像

2.5 查看刚刚构建的镜像

2.6 测试镜像,运行容器

2.7 访问测试

2.8 tomcat发布项目

2.9 上传镜像到DockerHub仓库

2.10 附环境变量JAVA_OPTS的设置

3、Dockerfile参考示例

示例1:构建Wordpress + nginx运行环境

示例2:构建Ruby on Rails环境

示例3: 构建Nginx运行环境

示例4:构建Postgres镜像

4、Dockerfile最佳实践

4.1 使用.dockerignore文件

4.2 避免安装不必要的软件包

4.3 每个容器都跑一个进程

4.4 最小化层

4.5 多行参数排序

4.6 创建缓存


1、基于已有镜像构建镜像并上传到DockerHub

构建镜像有很多方法,用户可以从 Docker Hub 获取已有镜像并更新,也可以利用本地文件系统Dockerfile创建一个。

1.1更改已安装的镜像容器

进入 mysql8.0.26 容器,命令:docker exec -it mysql8.0.26 bash,给容器安装上vim。

# 进入容器
docker exec -it mysql8.0.26 bash

# 测试vim命令结果:bash: vim: command not found
vim

# 更新索引
apt-get update

# 安装vim
apt-get install vim

# 测试vim命令结果:打开vim编辑器
vim

测试vim命令后退出容器

使用exit或按ctrl+p,ctrl+q退出容器。

1.2 基于上述容器重新创建镜像

镜像的完整名称是 用户名称/仓库名称:TAG ,创建的镜像计划上传到dockerhub服务器,所以创建的镜像名为kongzid/java:mysql8.0.26-vim。查看镜像列表可以看到已经创建的镜像。

# mysql8.0.26为刚才修改的容器名称,也可以用容器id
docker commit mysql8.0.26 kongzid/java:mysql8.0.26-vim

# 查看镜像列表
docker images

1.3 上传镜像到DockerHub仓库

使用docker login登录DockerHub后,上传镜像。注意这里的镜像名称必须和hub中的仓库名称一致,否则将会抛出错误。

# 登录
docker login

# 上传镜像到DockerHub的java仓库
docker push kongzid/java:mysql8.0.26-vim

查看dockerhub仓库 kongzid/java 已经存在tag为mysql8.0.26-vim的镜像。可以用docker pull kongzid/java:mysql8.0.26-vim下载镜像到本地。

2、使用Dockerfile构建JDK+tomcat镜像

使用 docker commit 来扩展一个镜像比较简单,但是不方便在一个团队中分享。我们可以使用 docker build 来创建一个新的镜像。为此,首先需要创建一个 Dockerfile,包含一些如何创建镜像的指令。

2.1 准备好jdk和tomcat安装包等文件

Jdk 和 Tomcat 记得从官网下载,否则制作出来的镜像容易出现不兼容问题。准备修改好的 server.xml (修改连接和线程数),制作镜像时覆盖tomcat中的;准备好以下5个文件,放在同一目录下。

apache-tomcat-8.5.32.tar.gz :tomcat9安装包    
jdk-8u181-linux-x64.tar.gz : jdk8安装包 
readme.txt : 说明文件
Dockerfile : 大小写要规范(注意Dockerfile的D需要大写),官方命名 Dockerfile,build 会自动寻找这个文件,若不是这个名字build时需要 -f 指定
server.xml : tomcat的配置文件,修改了部分配置,若使用默认配置不需要准备

2.2 编写Dockerfile文件

vim Dockerfile,文件内容如下:

# 指定操作的镜像
FROM ubuntu:20.04
 
# 维护者信息
MAINTAINER kongzi<153957433@qq.com>
 
# 覆盖相关文件
COPY readme.txt /usr/local/readme.txt
 
# 将 jdk 和 tomcat 添加到镜像ubuntu:20.04的/usr/local/目录下,ADD 命令会自动解压 将tar包解压到这个路径
ADD jdk-8u291-linux-x64.tar.gz /usr/local/
ADD apache-tomcat-9.0.54.tar.gz /usr/local/
 
# 安装一下基本命令,一般非必要不建议安装,尽量减少镜像内容
# Dockerfile 中每一条指令都创建镜像的一层,把多个命令可以用 && 合并
# RUN buildDeps='net-tools vim' \\
#     && apt-get update \\
#     && apt-get install -y $buildDeps \\
# 	&& apt-get purge -y --auto-remove $buildDeps
 
# 设置默认工作目录
ENV MYPATH /usr/local
WORKDIR $MYPATH
 
# 通过ENV来设置各种环境变量
ENV JAVA_HOME=/usr/local/jdk1.8.0_291
ENV JRE_HOME=/usr/local/jdk1.8.0_291/jre
ENV CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib
ENV CATALINA_HOME /usr/local/apache-tomcat-9.0.54
ENV CATALINA_BASH /usr/local/apache-tomcat-9.0.54
ENV PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin:$CATALINA_HOME/lib:$CATALINA_HOME/bin
ENV export JAVA_HOME JRE_HOME CLASSPATH PATH
# TZ在这里可以不设置,在容器启动的时候通过参数指定
ENV TZ="Asia/Shanghai"
# 可以设置tomcat参数
# ENV CATALINA_OPTS -Xms128m -Xmx1024m -XX:PermSize=64M -XX:MaxPermSize=512M
 
# 暴露端口8080
EXPOSE 8080
 
# 容器启动时运行tomcat && 拼接一些参数  tail -F 显示文件新追加的内容
CMD /usr/local/apache-tomcat-9.0.54/bin/catalina.sh run && tail -f /usr/local/apache-tomcat-9.0.54/logs/catalina.out

2.3 设置Dockerfile权限

设置Dockerfile权限: chmod 777 Dockerfile。该命令表示将这个文件改成所有的用户都可读可写可执行,若当前操作用户为root或有操作权限的用户,则不需要执行该操作。

2.4 执行 docker build 构建镜像

根据配置完的dockerfile构建Docker镜像,在Dockerfile文件所在的目录下使用docker build命令,注意命令最后的点 . 。

docker build -t java/tomcat9jdk8:v1.0 .
  • -t  设置tag名称, 命名规则 registry/image:tag(若不添加版本号,默认latest)

镜像构建完成

2.5 查看刚刚构建的镜像

使用 docker images 命令查看刚刚构建的镜像,在镜像列表中已经可以看到。

2.6 测试镜像,运行容器

使用docker run 命令运行容器,执行成功后使用 docker ps命令可以查看到运行的容器进程。

docker run -it -p 8090:8080  \\
--name tomcat9jdk8-my \\
--privileged=true \\
--restart=always \\
-v /usr/local/docker/tomcat/tomcat9/webapps:/usr/local/tomcat/webapps \\
-v /usr/local/docker/tomcat/tomcat9/conf:/usr/local/tomcat/conf \\
-v /usr/local/docker/tomcat/tomcat9/logs:/usr/local/tomcat/logs \\
-d java/tomcat9jdk8:v1.0
  • 默认情况下,tomcat会占用8080端口,所以在启动container的时候,指定了 -p 8090:8080,映射到宿主机端口就是8090。
  • -d 后台运行
  • --name tomcat9jdk8-my 容器名称
  • -v 挂载宿主机目录到tomcat下的webapps、conf、logs等,可以不指定
  • --privileged=true 设置拥有容器中的真正的root权限
  • java/tomcat9jdk8:v1.0 镜像的名称

附另外几种运行容器的命令:

# 只挂载代码(部署包)
docker run -it -p 8090:8080  \\
--name tomcat9jdk8-my \\
--privileged=true \\
--restart=always \\
-v /usr/local/docker/tomcat/tomcat9/webapps:/usr/local/tomcat/webapps \\
-d java/tomcat9jdk8:v1.0

# 只挂载挂载日志
docker run -it -p 8090:8080  \\
--name tomcat9jdk8-my \\
--privileged=true \\
--restart=always \\
-v /usr/local/docker/tomcat/tomcat9/logs:/usr/local/tomcat/logs \\
-d java/tomcat9jdk8:v1.0

# 只挂载配置文件catalina.sh(调整内存)
docker run -it -p 8090:8080  \\
--name tomcat9jdk8-my \\
--privileged=true \\
--restart=always \\
-v /usr/local/docker/tomcat/tomcat9/bin/catalina.sh:/usr/local/tomcat/bin/catalina.sh \\
-d java/tomcat9jdk8:v1.0

# 只挂载配置文件server.xml(调整端口和线程数)
docker run -it -p 8090:8080  \\
--name tomcat9jdk8-my \\
--privileged=true \\
--restart=always \\
-v /usr/local/docker/tomcat/tomcat9/conf/server.xml:/usr/local/tomcat/conf/server.xml \\
-d java/tomcat9jdk8:v1.0

2.7 访问测试

可以使用 curl http://localhost:8090 命令测试tomcat服务是否正常,也可以通过浏览器访问该网址。

2.8 tomcat发布项目

若使用挂载目录的方式运行的容器,只需要把项目war包放于挂载的webapps目录下,重启容器即可。

若使用非挂载的方式运行的容器,需要把war包放入容器内部的webapps目录下,重启容器即可。

  • 宿主机中使用命令如:docker cp /usr/demo.war tomcat9jdk8-my:/usr/local/tomcat/webapps
  • 进入容器内部命令: docker exec -it tomcat9jdk8-my /bin/bash

2.9 上传镜像到DockerHub仓库

1)使用docker hub 规范修改镜像的标签

# 使用docker hub 规范修改镜像的标签,注意命令的前后不能有空格
# docker tag <existing-image>  <hub-user>/<repo-name>[:<tag>]  
docker tag java/tomcat9jdk8:v1.0 kongzid/java:tomcat9jdk8V1

2)命令行登录docker hub并上传镜像

# 登录
docker login

# 上传镜像到DockerHub的java仓库
docker push kongzid/java:tomcat9jdk8V1

3)网页登录docker hub查看镜像

登录 Docker Hub 仓库中查看,可以看到已上传的镜像。

2.10 附环境变量JAVA_OPTS的设置

环境变量【JAVA_OPTS】可以在容器启动时指定:-e JAVA_OPTS='-server -Dfile.encoding=UTF-8 -Xms2g -Xmx2g -Xmn512m -Xss512K ..............',也可以在Dockerfile文件中指定。

ENV JAVA_OPTS="\\
-server \\
-Xms3g \\
-Xmx3g \\
-Xmn512m \\
-Xss512K \\
-Dfile.encoding=UTF-8 \\
-verbose:gc \\
-XX:+UseConcMarkSweepGC \\
-XX:MaxTenuringThreshold=10 \\
-XX:+ExplicitGCInvokesConcurrent \\
-XX:GCTimeRatio=19 \\
-XX:+UseParNewGC \\
-XX:+UseCMSCompactAtFullCollection \\
-XX:CMSFullGCsBeforeCompaction=10 \\
-XX:+CMSClassUnloadingEnabled \\
-XX:+CMSParallelRemarkEnabled \\
-XX:CMSInitiatingOccupancyFraction=50 \\
-Xnoclassgc \\
-XX:SoftRefLRUPolicyMSPerMB=0"

3、Dockerfile参考示例

示例1:构建Wordpress + nginx运行环境

# 指定基于的基础镜像
FROM ubuntu:14.04

# 维护者信息
MAINTAINER Eugene Ware <eugene@noblesamurai.com>

# Keep upstart from complaining
RUN dpkg-divert --local --rename --add /sbin/initctl
RUN ln -sf /bin/true /sbin/initctl

# Let the conatiner know that there is no tty
ENV DEBIAN_FRONTEND noninteractive

RUN apt-get update
RUN apt-get -y upgrade

# Basic Requirements
RUN apt-get -y install mysql-server mysql-client nginx php5-fpm php5-mysql php-apc pwgen python-setuptools curl git unzip

# Wordpress Requirements
RUN apt-get -y install php5-curl php5-gd php5-intl php-pear php5-imagick php5-imap php5-mcrypt php5-memcache php5-ming php5-ps php5-pspell php5-recode php5-sqlite php5-tidy php5-xmlrpc php5-xsl

# mysql config, 配置MySQL运行参数
RUN sed -i -e"s/^bind-address\\s*=\\s*127.0.0.1/bind-address = 0.0.0.0/" /etc/mysql/my.cnf

# nginx config, 配置Nginx运行参数
RUN sed -i -e"s/keepalive_timeout\\s*65/keepalive_timeout 2/" /etc/nginx/nginx.conf
RUN sed -i -e"s/keepalive_timeout 2/keepalive_timeout 2;\\n\\tclient_max_body_size 100m/" /etc/nginx/nginx.conf
RUN echo "daemon off;" >> /etc/nginx/nginx.conf

# php-fpm config
RUN sed -i -e "s/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/g" /etc/php5/fpm/php.ini
RUN sed -i -e "s/upload_max_filesize\\s*=\\s*2M/upload_max_filesize = 100M/g" /etc/php5/fpm/php.ini
RUN sed -i -e "s/post_max_size\\s*=\\s*8M/post_max_size = 100M/g" /etc/php5/fpm/php.ini
RUN sed -i -e "s/;daemonize\\s*=\\s*yes/daemonize = no/g" /etc/php5/fpm/php-fpm.conf
RUN sed -i -e "s/;catch_workers_output\\s*=\\s*yes/catch_workers_output = yes/g" /etc/php5/fpm/pool.d/www.conf
RUN find /etc/php5/cli/conf.d/ -name "*.ini" -exec sed -i -re 's/^(\\s*)#(.*)/\\1;\\2/g'  \\;

# nginx site conf,将本地Nginx配置文件复制到容器中的目录
ADD ./nginx-site.conf /etc/nginx/sites-available/default

# Supervisor Config
RUN /usr/bin/easy_install supervisor
RUN /usr/bin/easy_install supervisor-stdout
ADD ./supervisord.conf /etc/supervisord.conf

# Install Wordpress
ADD https://wordpress.org/latest.tar.gz /usr/share/nginx/latest.tar.gz
RUN cd /usr/share/nginx/ && tar xvf latest.tar.gz && rm latest.tar.gz
RUN mv /usr/share/nginx/html/5* /usr/share/nginx/wordpress
RUN rm -rf /usr/share/nginx/www
RUN mv /usr/share/nginx/wordpress /usr/share/nginx/www
RUN chown -R www-data:www-data /usr/share/nginx/www

# Wordpress Initialization and Startup Script
ADD ./start.sh /start.sh
RUN chmod 755 /start.sh

# private expose
EXPOSE 3306
EXPOSE 80

# volume for mysql database and wordpress install
VOLUME ["/var/lib/mysql", "/usr/share/nginx/www"]

# 容器启动时执行命令
CMD ["/bin/bash", "/start.sh"]

示例2:构建Ruby on Rails环境

# 指定基础镜像
FROM fcat/ubuntu-universe:12.04

# development tools
RUN apt-get -qy install git vim tmux

# ruby 1.9.3 and build dependencies
RUN apt-get -qy install ruby1.9.1 ruby1.9.1-dev build-essential libpq-dev libv8-dev libsqlite3-dev

# bundler
RUN gem install bundler

# create a "rails" user
# the Rails application will live in the /rails directory
RUN adduser --disabled-password --home=/rails --gecos "" rails

# copy the Rails app
# we assume we have cloned the "docrails" repository locally
#  and it is clean; see the "prepare" script
ADD docrails/guides/code/getting_started /rails

# Make sure we have rights on the rails folder
RUN chown rails -R /rails

# copy and execute the setup script
# this will run bundler, setup the database, etc.
ADD scripts/setup /setup
RUN su rails -c /setup

# copy the start script
ADD scripts/start /start

EXPOSE 3000

# 创建用户
USER rails

# 设置容器启动命令
CMD /start

示例3: 构建Nginx运行环境

# 指定基础镜像
FROM sameersbn/ubuntu:14.04.20161014

# 维护者信息
MAINTAINER sameer@damagehead.com

# 设置环境
ENV RTMP_VERSION=1.1.10 \\
    NPS_VERSION=1.11.33.4 \\
    LIBAV_VERSION=11.8 \\
    NGINX_VERSION=1.10.1 \\
    NGINX_USER=www-data \\
    NGINX_SITECONF_DIR=/etc/nginx/sites-enabled \\
    NGINX_LOG_DIR=/var/log/nginx \\
    NGINX_TEMP_DIR=/var/lib/nginx \\
    NGINX_SETUP_DIR=/var/cache/nginx

# 设置构建时变量,镜像建立完成后就失效
ARG BUILD_LIBAV=false
ARG WITH_DEBUG=false
ARG WITH_PAGESPEED=true
ARG WITH_RTMP=true

# 复制本地文件到容器目录中
COPY setup/ $NGINX_SETUP_DIR/
RUN bash $NGINX_SETUP_DIR/install.sh

# 复制本地配置文件到容器目录中
COPY nginx.conf /etc/nginx/nginx.conf
COPY entrypoint.sh /sbin/entrypoint.sh

# 运行指令
RUN chmod 755 /sbin/entrypoint.sh

# 允许指定的端口
EXPOSE 80/tcp 443/tcp 1935/tcp

# 指定网站目录挂载点
VOLUME ["$NGINX_SITECONF_DIR"]

ENTRYPOINT ["/sbin/entrypoint.sh"]
CMD ["/usr/sbin/nginx"]

示例4:构建Postgres镜像

# 指定基础镜像
FROM sameersbn/ubuntu:14.04.20161014

# 维护者信息
MAINTAINER sameer@damagehead.com

# 设置环境变量
ENV PG_APP_HOME="/etc/docker-postgresql"\\
    PG_VERSION=9.5 \\
    PG_USER=postgres \\
    PG_HOME=/var/lib/postgresql \\
    PG_RUNDIR=/run/postgresql \\
    PG_LOGDIR=/var/log/postgresql \\
    PG_CERTDIR=/etc/postgresql/certs

ENV PG_BINDIR=/usr/lib/postgresql/$PG_VERSION/bin \\
    PG_DATADIR=$PG_HOME/$PG_VERSION/main

# 下载PostgreSQL
RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add - \\
 && echo 'deb http://apt.postgresql.org/pub/repos/apt/ trusty-pgdg main' > /etc/apt/sources.list.d/pgdg.list \\
 && apt-get update \\
 && DEBIAN_FRONTEND=noninteractive apt-get install -y acl \\
      postgresql-$PG_VERSION postgresql-client-$PG_VERSION postgresql-contrib-$PG_VERSION \\
 && ln -sf $PG_DATADIR/postgresql.conf /etc/postgresql/$PG_VERSION/main/postgresql.conf \\
 && ln -sf $PG_DATADIR/pg_hba.conf /etc/postgresql/$PG_VERSION/main/pg_hba.conf \\
 && ln -sf $PG_DATADIR/pg_ident.conf /etc/postgresql/$PG_VERSION/main/pg_ident.conf \\
 && rm -rf $PG_HOME \\
 && rm -rf /var/lib/apt/lists/*

COPY runtime/ $PG_APP_HOME/
COPY entrypoint.sh /sbin/entrypoint.sh
RUN chmod 755 /sbin/entrypoint.sh

# 指定端口
EXPOSE 5432/tcp

# 指定数据挂载点
VOLUME ["$PG_HOME", "$PG_RUNDIR"]

# 切换目录
WORKDIR $PG_HOME

# 设置容器启动时执行命令
ENTRYPOINT ["/sbin/entrypoint.sh"]

4、Dockerfile最佳实践

4.1 使用.dockerignore文件

为了在docker build过程中更快上传和更加高效,应该使用一个.dockerignore文件用来排除构建镜像时不需要的文件或目录。例如,除非.git在构建过程中需要用到,否则你应该将它添加到.dockerignore文件中,这样可以节省很多时间。

4.2 避免安装不必要的软件包

为了降低复杂性、依赖性、文件大小以及构建时间,应该避免安装额外的或不必要的包。例如,不需要在一个数据库镜像中安装一个文本编辑器。

4.3 每个容器都跑一个进程

在大多数情况下,一个容器应该只单独跑一个程序。解耦应用到多个容器使其更容易横向扩展和重用。如果一个服务依赖另外一个服务,可以参考 Linking Containers Together。

4.4 最小化层

我们知道每执行一个指令,都会有一次镜像的提交,镜像是分层的结构,对于 Dockerfile,应该找到可读性和最小化层之间的平衡。

4.5 多行参数排序

如果可能,通过字母顺序来排序,这样可以避免安装包的重复并且更容易更新列表,另外可读性也会更强,添加一个空行使用 \\ 换行:

RUN apt-get update && apt-get install -y \\
  bzr \\
  cvs \\
  git \\
  mercurial \\
  subversion

4.6 创建缓存

镜像构建过程中会按照 Dockerfile 的顺序依次执行,每执行一次指令 Docker 会寻找是否有存在的镜像缓存可复用,如果没有则创建新的镜像。如果不想使用缓存,则可以在docker build 时添加--no-cache=true选项。

从基础镜像开始就已经在缓存中了,下一个指令会对比所有的子镜像寻找是否执行相同的指令,如果没有则缓存失效。在大多数情况下只对比 Dockerfile 指令和子镜像就足够了。ADD 和 COPY 指令除外,执行 ADD 和 COPY 时存放到镜像的文件也是需要检查的,完成一个文件的校验之后再利用这个校验在缓存中查找,如果检测的文件改变则缓存失效。RUN apt-get -y update命令只检查命令是否匹配,如果匹配就不会再执行更新了。

为了有效地利用缓存,你需要保持你的Dockerfile一致,并且尽量在末尾修改。

以上是关于Docker教程-9-构建镜像并上传到DockerHub仓库的主要内容,如果未能解决你的问题,请参考以下文章

Docker教程-9-构建镜像并上传到DockerHub仓库

制作自己的docker镜像并上传到hub.docker

实验:构建第一个Docker镜像

docker教程——docker镜像打包上传

构建最小JDK Docker镜像

docker jetty10 启动 war