Dockerfile构建镜像

Docker 在镜像的设计中,引入了层(layer)的概念。也就是说,用户制作镜像的每一步操作,都会生成一个层,也就是一个增量rootfs。

        

第一部分:只读层。
它是这个容器的 rootfs 最下面的五层,对应的正是 ubuntu:latest 镜像的五层。可以看到,它们的挂载方式都是只读的(ro+wh,即 readonly+whiteout,至于什么是 whiteout?)。
第二部分:可读写层。
它是这个容器的 rootfs 最上面的一层,它的挂载方式为:rw,即 read write。在没有写入文件之前,这个目录是空的。而一旦在容器里做了写操作,你修改产生的内容就会以增量的方式出现在这个层中。
这个可读写层的作用,就是专门用来存放你修改 rootfs 后产生的增量,无论是增、删、改,都发生在这里。而当我们使用完了这个被修改过的容器之后,还可以使用 docker commit 和 push 指令,保存这个被修改过的可读写层,并上传到 Docker Hub 上,供其他人使用;而与此同时,原先的只读层里的内容则不会有任何变化。这,就是增量rootfs 的好处。
第三部分:Init 层。
它是一个以“-init”结尾的层,夹在只读层和读写层之间。Init 层是 Docker 项目单独生成的一个内部层,专门用来存放 /etc/hosts、/etc/resolv.conf 等信息。
需要这样一层的原因是,这些文件本来属于只读的 Ubuntu 镜像的一部分,但是用户往往需要在启动容器时写入一些指定的值比如 hostname,所以就需要在可读写层对它们进行修改。
可是,这些修改往往只对当前的容器有效,我们并不希望执行 docker commit 时,把这些信息连同可读写层一起提交掉。所以,Docker 做法是,在修改了这些文件之后,以一个单独的层挂载了出来。而用户执行 docker commit 只会提交可读写层,所以是不包含这些内容的。

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和操作命令;每一条指令构建一层镜像,因此每一条指令的内容,就是描述该层镜像应当如何构建(也就是你要执行的操作命令)

 1 Dockerfile指令集

FROM 这个镜像的妈妈是谁?(指定基础镜像)

MAINTAINER 告诉别人,谁负责养它?(指定维护者信息,可以没有)LABLE key=values

RUN 你想让它干啥(在命令前面加上RUN即可)

ADD/COPY 给它点创业资金(COPY文件,会自动解压)

WORKDIR 我是cd,今天刚化了妆(设置当前工作目录)

VOLUME 给它一个存放行李的地方(设置卷,挂载主机目录)

EXPOSE 它要打开的门是啥(指定对外的端口)

CMD 奔跑吧,兄弟!(指定容器启动后的要干的事情)

ENTRYPOINT  容器启动命名

ENV 环境变量

USER 切换用户

Docker 提供了一种更便捷的方式,叫作 Dockerfile

docker build命令用于根据给定的Dockerfile构建Docker镜像 

docker build语法: 

 # docker build [OPTIONS] <PATH | URL | ->

1. 常用选项说明
--build-arg,设置构建时的变量
--no-cache,默认false。设置该选项,将不使用Build Cache构建镜像
--pull,默认false。设置该选项,总是尝试pull镜像的最新版本
--compress,默认false。设置该选项,将使用gzip压缩构建的上下文
--disable-content-trust,默认true。设置该选项,将对镜像进行验证
--file, -f,Dockerfile的完整路径,默认值为‘PATH/Dockerfile’
--isolation,默认--isolation="default",即Linux命名空间;其他还有process或hyperv
--label,为生成的镜像设置metadata
--squash,默认false。设置该选项,将新构建出的多个层压缩为一个新层,但是将无法在多个镜像之间共享新层;设置该选项,实际上是创建了新image,同时保留原有image。
--tag, -t,镜像的名字及tag,通常name:tag或者name格式;可以在一次构建中为一个镜像设置多个tag
--network,默认default。设置该选项,Set the networking mode for the RUN instructions during build
--quiet, -q ,默认false。设置该选项,Suppress the build output and print image ID on success
--force-rm,默认false。设置该选项,总是删除掉中间环节的容器
--rm,默认--rm=true,即整个构建过程成功后删除中间环节的容器 

示例: 
docker build -t soso/bbauto:v2.1 .

docker build  是docker创建镜像的命令 
-t 是标识新建的镜像属于 soso的 bbauto镜像 
:v2.1 是tag 
"."是用来指明 我们的使用的Dockerfile文件当前目录的(也可以跟绝对路径)

  2.1、 创建镜像所在的文件夹和Dockerfile文件 

[root@docker-server ~]# mkdir sinatra
[root@docker-server ~]# cd sinatra/
[root@docker-server sinatra]# touch Dockerfile

2.2、 在Dockerfile文件中写入指令,每一条指令都会更新镜像的信息例如:

[root@docker-server sinatra]# vim Dockerfile
#This is a comment 
FROM daocloud.io/library/centos:7  #基于哪个基础镜像
MAINTAINER soso soso@docker-server  #指定作者(可选)
RUN touch a.txt
RUN mkdir /test
RUN yum -y install vim

格式说明:

命令要大写,"#"是注解。 
每一个指令后面需要跟空格,语法。:q
FROM 命令是告诉docker 我们的镜像什么从哪里下载。 
MAINTAINER 是描述 镜像的创建人。 
RUN 命令是在镜像内部执行。就是说他后面的命令应该是针对镜像可以运行的命令。

2.3、创建镜像

命令:
# docker build -t soso/centos:7 . 

docker build  是docker创建镜像的命令

详细执行过程:

[root@docker-server sinatra]# docker build -t soso/centos:7 . 
Sending build context to Docker daemon  2.048kB
Step 1/4 : FROM daocloud.io/library/centos
latest: Pulling from library/centos
d8d02d457314: Pull complete 
Digest: sha256:a36b9e68613d07eec4ef553da84d0012a5ca5ae4a830cf825bb68b929475c869
Status: Downloaded newer image for daocloud.io/library/centos:latest
 ---> 67fa590cfc1c
Step 2/4 : MAINTAINER soso soso@docker-server
 ---> Running in aab3d80939d8
Removing intermediate container aab3d80939d8
 ---> 12bae7d75a23
....

2.4、创建完成后,从镜像创建容器

2.4、创建完成后,从镜像创建容器

单阶段构建镜像 

#下载基础镜像
docker pull nginx

#编写Dockerfile
vim Dockerfile
FROM nginx
CMD ["nginx","-g","daemon off;"]

#构建镜像
docker build -t nginx:v1.1 .

#运行容器
docker run -itd --name nginx -p 80:80 nginx:v1.1

#查看容器
docker ps

 页面访问nginx即可多阶段构建镜像#编写Dockerfile


FROM nginx:v1.1 as builder

FROM centos
RUN mkdir /test
COPY --from=builder /etc/nginx/nginx.conf /test

#构建镜像
docker build -t centos:v1.2 .

#查看镜像
docker images

#起容器验证,centos中的文件是否拷贝过来

 Dockerfile(Jenkins)

做实验之前,必须得把宿主机的ipv4路由转发功能打开(如果遇到容器访问不到的情况)
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p
1.创建一个jenkins的Dockerfile
[root@docker-server ~]# mkdir tomcat 
[root@docker-server ~]# cd tomcat/
将以下安装包拷贝至tomcat目录中
[root@docker-server1 tomcat]# ls
apache-tomcat-8.5.47.tar.gz  Dockerfile  jdk-8u211-linux-x64.tar.gz  jenkins.war
[root@docker-server tomcat]# vim Dockerfile
# This my first jenkins Dockerfile
# Version 1.0

FROM centos:7
MAINTAINER docker-server
ENV JAVA_HOME /usr/local/jdk1.8.0_211
ENV TOMCAT_HOME /usr/local/apache-tomcat-8.5.47
ENV PATH=$JAVA_HOME/bin:$PATH
ADD apache-tomcat-8.5.47.tar.gz /usr/local/  
ADD jdk-8u211-linux-x64.tar.gz /usr/local/
RUN rm -rf /usr/local/apache-tomcat-8.5.47/webapps/*
ADD jenkins.war /usr/local/apache-tomcat-8.5.47/webapps
RUN rm -rf apache-tomcat-8.5.47.tar.gz  jdk-8u211-linux-x64.tar.gz
EXPOSE 8080
ENTRYPOINT ["/usr/local/apache-tomcat-8.5.47/bin/catalina.sh","run"]  #运行命令

[root@docker-server tomcat]# pwd
/root/tomcat

[root@docker-server tomcat]# ls  #将jdk与tomcat还有jenkins的包上传到tomcat目录中
apache-tomcat-8.5.47.tar.gz  Dockerfile  jdk-8u211-linux-x64.tar.gz  jenkins.war
[root@docker-server tomcat]# docker build -t jenkins:v1 .
[root@docker-server tomcat]# docker run -itd --name jenkins1 -p 8081:8080 jenkins:v1

Dockerfile(Nginx)

FROM centos:7

RUN buildDeps='readline-devel pcre-devel openssl-devel gcc telnet wget curl make' \
&& useradd -M -s /sbin/nologin nginx \
&& mkdir -p /usr/local/nginx/conf/vhost \
&& mkdir -p /data/logs/nginx \
&& yum -y install $buildDeps \
&& yum clean all \
&& wget http://nginx.org/download/nginx-1.23.4.tar.gz \
&& tar zxf nginx-1.23.4.tar.gz \
&& cd nginx-1.23.4 \
&& ./configure --prefix=/usr/local/nginx \
    --with-http_ssl_module \
    --with-http_stub_status_module \
&& make -j 1 && make install \
&& rm -rf /usr/local/nginx/html/* \
&& echo "linux cloud 2301" >> /usr/local/nginx/html/cloud.html \
&& cd / && rm -rf nginx-1.23.4* \
&& ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
 
ENV PATH /usr/local/nginx/sbin:$PATH
COPY nginx.conf /usr/local/nginx/conf/nginx.conf
WORKDIR /usr/local/nginx
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]  #前台显示,长时间驻留

 # docker run -itd --name nginx1 -p 8082:80 nginx:1.23.4

 CMD与ENTRYPOINT区别

一、Dockerfile中的CMD

CMD如果使用dockerfile时用的是CMD,那么启动容得时候就不需要加解释器了,如果加了解释器,那么CMD就失效了
ENTRYPOINT如果使用dockerfile时用ENTRYPOINT,那么启动容器时加不加解释器就无所谓了,命令都会执行

1、每个Dockerfile中只能有一个CMD如果有多个那么只执行最后一个。
2、CMD 相当于启动docker时候后面添加的参数看,举个简单例子:
# docker run -itd --name test image(镜像) /bin/bash -c
a、镜像名称后面跟了一个/bin/bash -c ,其实等价于在dockerfile中的CMD ["/bin/bash","-c"]。
b、如果dockerfile中的CMD中有了CMD["/bin/bash","-c"],那么就不用在执行的时候再添加了,如果添加了参数的话那么就相当于要执行你添加的参数,默认的CMD中的参数就无效了。

二、Dockerfile中的ENTRYPOINT
1、一个Dockerfile中ENTRYPOINT也只能存在一个,若存在多个那么只执行最后一个,你可以理解为开机启动的意思,和CMD有点像,不过还是有区别。

2、举个简单例子:
a、Dockerfile中有ENTRYPOINT ["tail","-f","/var/log/nginx/access.log"],那么启动的时候镜像就执行了这个里面的内容,如果你像上面带参数的话就相当于在这个执行的内容后面再加入参数。
案例:
如果我们的dockerfile中有a中的这句话然后我们启动我们的docker:
# docker run -itd --name test image(镜像名) /bin/bash -c

此时就相当于我们启动docker的时候执行了:tail -f /var/log/nginx/access.log /bin/bash -c
这个命令明显就不对.

Dockerfile优化 

1、多阶段构建镜像
使用多个FROM指令,将构建过程分为多个阶段;每个阶段生成一个独立的镜像,后续阶段可以使用前面阶段生成的镜像作为基础镜像。多阶段构建可以有效减小最终镜像的体积,分离构建环境和运行环境多阶段构建。它允许在一个Dockerfile中使用多个FROM指令,每个FROM指令都可以使用不同的基础镜像,并且每个FROM指令都开始一个新的构建阶段。多阶段构建的主要目的是**将构建过程分为多个独立的阶段**,**每个阶段生成一个独立的镜像**。后续阶段可以使用前面阶段生成的镜像作为基础镜像,从而实现构建环境和运行环境的分离,有效减小最终镜像的体积。

2、把不需要的命令输出丢入/dev/null
对于某些命令的标准输出和错误输出,如果不需要,可以重定向到/dev/null,避免不必要的输出写入镜像层,减小镜像体积。使用command > /dev/null 2>&1的形式进行重定向

3、使用普通用户运行
在Dockerfile中使用USER指令切换到非root用户,以最小权限原则运行应用,提高安全性。确保应用程序有足够权限访问所需资源

4、选择合适的基础镜像
Alpine Linux是一个面向安全的轻型Linux发行版,镜像体积小,相比Ubuntu、CentOS等,Alpine Linux更适合作为基础镜像,务必评估Alpine Linux与应用程序的兼容性。

5、减少镜像层数
1、RUN 命令要尽量写在一条里,每次 RUN 命令都是在之前的镜像上封装,只会增大不会减小

6、每次进行依赖安装后,记得yum clean all

部署私有仓库应用

私有仓库镜像:
registry  --官方出品, 没有图形界面。Docker hub官方已提供容器镜像registry,用于搭建私有仓库
拉取镜像:

[root@docker-server ~]# docker pull daocloud.io/library/registry:latest

运行容器:

[root@docker-server ~]# docker run -itd -v /home/dockerdata/registry:/var/lib/registry --name "pri_registry" --restart=always -p 5000:5000 daocloud.io/library/registry:latest

参数解释:
/home/dockerdata/registry表示为宿主机的目录,如果不存在自动创建
-v映射目录:  宿主机的目录:容器目录
把宿主机的目录挂载到容器中,将数据目录挂载出来就是为了防止docker私有仓库这个容器被删除的时候,仓库里面的镜像也被删除。
-p 端口映射:本地端口:容器端口

注:如果创建容器不成功,报错防火墙,解决方案如下

# systemctl stop firewalld
# yum install iptables*
# systemctl start iptables
# iptables -F
# systemctl restart docker

 [root@docker-server ~]# docker ps 


连接容器查看端口状态:

 [root@docker-server ~]# docker exec -it  0823df7  /bin/sh
/ # netstat -lntp    #查看5000端口是否开启
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name    
tcp        0      0 :::5000                 :::*                    LISTEN      1/registry

在本机查看能否访问该私有仓库, 看看状态码是不是200

 [root@docker-server ~]# curl -I http://127.0.0.1:5000


为了测试,下载1个比较小的镜像,b[root@docker-server ~]# docker pull daocloud.io/library/busyboxusybox

[root@docker-server ~]# docker pull daocloud.io/library/busybox

上传前必须给镜像打tag  注明ip和端口:

[root@docker-server ~]# docker tag daocloud.io/library/busybox 192.168.246.141:5000/busybox

下面这个Mysql是我测试的第二个镜像,从daocloud拉取的:

[root@docker-server ~]# docker pull daocloud.io/library/mysql
[root@docker-server ~]# docker tag daocloud.io/library/mysql 192.168.246.141:5000/daocloud.io/library/mysql
[root@docker-server ~]# docker images

注:tag后面可以使用镜像名称也可以使用id,我这里使用的镜像名称,如果使用官方的镜像,不需要加前缀,但是daocloud.io的得加前缀.

[root@docker-server ~]# docker push 10.8.166.252:5000/busybox:latest
现在推送,会报下面错误: 


修改请求方式为http:

默认为https,不改会报以下错误:
Get https://master.up.com:5000/v1/_ping: http: server gave HTTP response to HTTPS client

[root@docker-server ~]# vim /etc/docker/daemon.json    #不存在则创建
{ "insecure-registries":["192.168.246.141:5000"] }


注释:第一行是Docker镜像加速器。后面一定要跟逗号;第二行是仓库地址

重启docker:
[root@docker-server ~]# systemctl restart docker

上传镜像到私有仓库:

[root@docker-server ~]# docker push 192.168.246.141:5000/busybox
[root@docker-server ~]# docker push 192.168.246.141:5000/daocloud.io/library/mysql

宿主机查看存放镜像目录:
[root@docker-server ~]# ls /home/dockerdata/registry/docker/registry/v2/repositories/

查看私有仓库里的所有镜像:

这条命令会查看仓库下面所有的镜像:
[root@docker-server ~]# curl http://192.168.246.141:5000/v2/_catalog

语法: # curl  http://ip:port/v2/repo名字/tags/list
[root@docker-server ~]# curl http://192.168.246.141:5000/v2/busybox/tags/list
{"name":"busybox","tags":["latest"]}

[root@docker-server ~]# curl http://192.168.246.141:5000/v2/daocloud.io/li    brary/mysql/tags/list
{"name":"daocloud.io/library/mysql","tags":["latest"]} 

拉取镜像测试:

1.先将刚才打了tags的镜像删掉
[root@docker-server ~]# docker rmi 192.168.246.141:5000/busybox
2.拉取镜像:
[root@docker-server ~]# docker pull 192.168.246.141:5000/busybox
[root@docker-server ~]# docker images

docker页面管理工具

下载并运行容器:

[root@docker-server ~]# docker pull uifd/ui-for-docker
[root@docker-server ~]# docker run -it -d --name docker-web -p 9000:9000 -v /var/run/docker.sock:/var/run/docker.sock docker.io/uifd/ui-for-docker

浏览器访问测试:
ip:9000

systemctl启动服务

镜像下载:

[root@docker-server ~]# docker pull daocloud.io/library/centos:7

systemd 整合:

因为 systemd 要求 CAPSYSADMIN 权限,从而得到了读取到宿主机 cgroup 的能力,CentOS7 中已经用 fakesystemd 代替了 systemd 。 但是我们使用systemd,可用参考下面的 Dockerfile:

[root@docker-server ~]# mkdir test
[root@docker-server ~]# cd test/
[root@docker-server test]# vim Dockerfile
FROM daocloud.io/library/centos:7
MAINTAINER "soso"  soso@qq.com
ENV container docker

RUN yum -y swap -- remove fakesystemd -- install systemd systemd-libs
RUN yum -y update; yum clean all; \
(cd /lib/systemd/system/sysinit.target.wants/; for i in *; do [ $i == systemd-tmpfiles-setup.service ] || rm -f $i; done); \
rm -f /lib/systemd/system/multi-user.target.wants/*;\
rm -f /etc/systemd/system/*.wants/*;\
rm -f /lib/systemd/system/local-fs.target.wants/*; \
rm -f /lib/systemd/system/sockets.target.wants/*udev*; \
rm -f /lib/systemd/system/sockets.target.wants/*initctl*; \
rm -f /lib/systemd/system/basic.target.wants/*;\
rm -f /lib/systemd/system/anaconda.target.wants/*;

VOLUME [ "/sys/fs/cgroup" ]   #指定逻辑卷

CMD ["/usr/sbin/init"]     #代表的是把上面的服务拉起来

这个Dockerfile删除fakesystemd 并安装了 systemd。然后再构建基础镜像:

[root@docker-server test]# dockemd 的

r build -t local/c7-systemd .

执行没有问题这就生成一个包含 syste

应用容器示例

[root@docker-server test]# docker images
REPOSITORY         TAG           执行没有问题这就生成一个包含 systemd 的应用容器示例      IMAGE ID            CREATED             SIZE
local/c7-systemd   latest              a153dcaa642e        6 minutes ago       391MB

为了使用像上面那样包 systemd 的含容器,需要创建一个类似下面的Dockerfile:

[root@docker-server test]# mkdir http
[root@docker-server test]# cd http/
[root@docker-server http]# vim Dockerfile
FROM local/c7-systemd
RUN yum -y install httpd; yum clean all; systemctl enable httpd.service
EXPOSE 80
CMD ["/usr/sbin/init"]

或者
[root@docker-server http]# cat Dockerfile 
FROM local/c7-systemd
RUN rm -rf /etc/yum.repos.d/*
ADD Centos-7.repo /etc/yum.repos.d/
RUN yum -y install httpd; yum clean all; systemctl enable httpd
EXPOSE 80
CMD ["/usr/sbin/init"]

构建镜像:

 [root@docker-server http]# docker build -t local/c7-systemd-httpd .

运行包含 systemd 的应用容器:

为了运行一个包含 systemd 的容器,需要使用--privileged选项, 并且挂载主机的 cgroups 文件夹。 下面是运行包含 systemd 的 httpd 容器的示例命令:

[root@docker-server http]# docker run --privileged -tid -v /sys/fs/cgroup:/sys/fs/cgroup:ro -p 80:80 local/c7-systemd-httpd

--privileged:授权提权。让容器内的root用户拥有真正root权限(有些权限是没有的)
ro代表的是只读
rw代表的是读写

注意:如果不加会运行在前台(没有用-d),可以用ctrl+p+q放到后台去

测试可用:

[root@docker-server http]# yum install -y elinks
[root@docker-server http]# elinks --dump http://192.168.246.141 #apache的默认页面
                                 Testing 123..

   This page is used to test the proper operation of the [1]Apache HTTP
   server after it has been installed. If you can read this page it means
   that this site is working properly. This server is powered by [2]CentOS.

再来个安装openssh-server的例子:

[root@docker-server http]# cd ..
[root@docker-server test]# mkdir ssh
[root@docker-server test]# cd ssh/
[root@docker-server ssh]# vim Dockerfile
FROM local/c7-systemd
RUN yum -y install openssh-server; yum clean all; systemctl enable sshd.service
RUN echo 123456 | passwd --stdin root
EXPOSE 22
CMD ["/usr/sbin/init"]
[root@docker-server ssh]# docker build -t local/c7-systemd-sshd .
[root@docker-server ssh]# docker run --privileged -tid -v /sys/fs/cgroup:/sys/fs/cgroup:ro -p 2222:22 local/c7-systemd-sshd
[root@docker-server ssh]# ssh 192.168.246.141 -p 2222
[root@ce1af52a6f6c ~]#

修改Docker数据存储位置

查看存储路径:
[root@docker-server ~]# docker info | grep Root
 Docker Root Dir: /var/lib/docker

修改默认存储位置:
在ExecStart的启动命令后面追加--data-root参数指定新的位置
[root@docker-server ~]# vim  /usr/lib/systemd/system/docker.service
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --data-root=/data

[root@docker-server ~]# systemctl daemon-reload 
[root@docker-server ~]# systemctl restart docker

查看是否生效:
[root@docker-server ~]# docker info | grep Root
 Docker Root Dir: /data
 
[root@docker-server ~]# cd /data/
[root@docker-server data]# ls
builder  buildkit  containers  image  network  overlay2  plugins  runtimes  swarm  tmp  trust  volumes

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值