docker官方和个人发布的镜像由于版本等各种原因,漏洞较多,已统计Docker Hub超过30%的官方镜像包含高位漏洞。此外,由于网络等原因也会造成docker pull 下载镜像的速度很慢。基于这种情况,我们可以手动定制docker系统镜像。构建镜像的方式有两种:
方式一:docker commit
步骤1:拉取一个基础镜像(其实就是OS)
docker pull centos
docker run -it --name mycentos centos /bin/bash
这里的 ll 命令找不到,可能是因为版本问题,这个不影响,想要使用参考解决 ll 命令无法使用
步骤3:将需要的资源上传到宿主机上
注意!!!:本例是制作一个tomcat镜像,所以需要这些资源
步骤4:将宿主机上的资源拷贝到容器
docker cp apache-tomcat-7.0.64.tar.gz mycentos:/root
docker cp jdk-8u181-linux-x64.tar.gz mycentos:/root
# 解压jdk到/usr/local/目录下
tar -zxvf jdk-8u181-linux-x64.tar.gz -C /usr/local/
# 打开profile文件,配置环境
vi /etc/profile
这里就跟Linux安装jdk一样的,配置好之后刷新一下,就可以了
步骤6:在容器安装tomcat,解压并配置
# 解压tomcat到/usr/local/目录下
tar -zxvf apache-tomcat-7.0.64.tar.gz -C /usr/local/
# 编辑tomcat的setclsspath.sh文件
vi /usr/local/apache-tomcat-7.0.64/bin/setclasspath.sh
步骤7:将运行的mycentos容器提交为一个新的镜像,新的镜像名称为mytomcat
docker commit mycentos mytomcat
到这里,我们的镜像就已经制作好了
基于mytomcat镜像创建一个容器
docker run -itd --name t1 -p 8888:8080 mytomcat /bin/bash
#进入容器,并去执行startup.sh文件
docker exec t1 /usr/local/apache-tomcat-7.0.64/bin/startup.sh
#1,镜像打包
docker save -o /root/tomcat7.tar mytomcat
#2,将打包的镜像上传到其他服务器
scp tomcat7.tar 其他服务器ip:.root
#1,容器打包
docker export -o /root/t1.tar t1
#2,导入容器
docker import t1.tar mytomcat:latest
docker load -i /root/tomcat7.tar
至此算是完成了
方式二:docker builder
Dockerfile使用基本的基于DSL语法的指令来构建一个Docker镜像,之后使用docker builder命令基于该Dockerfile中的指令构建一个新的镜像
DSL语法:
1)FROM(指定基础image)
构建指令,必须指定且需要在Dockerfile其他指令的前面。后续的指令都依赖于该指令指定的image。FROM指令指定的基础image可以是官方远程仓库中的,也可以位于本地仓库。
FROM命令告诉docker我们构建的镜像是以哪个(发行版)镜像为基础的。第一条指令必须是FROM指令。并且,如果在同一个Dockerfile中创建多个镜像时,可以使用多个 FROM 指令。
该指令有两种格式:
FROM
指定基础image为该image的最后修改的版本。或者:
FROM :
指定基础image为该image的一个tag版本。
RUN后面接要执行的命令,比如,我们想在镜像中安装vim,只需在Dockfile中写入 RUN yum install -y vim
2)MAINTAINER(用来指定镜像创建者信息)
构建指令,用于将image的制作者相关的信息写入到image中。当我们对该image执行docker inspect命令时,输出中有相应的字段记录该信息。
格式:
MAINTAINER
3)RUN(安装软件用)
构建指令,RUN可以运行任何被基础image支持的命令。如基础image选择了ubuntu,那么软件管理部分只能使用ubuntu的命令。
该指令有两种格式:
RUN
4)CMD(设置container启动时执行的操作)
设置指令,用于container启动时指定的操作。该操作可以是执行自定义脚本,也可以是执行系统命令。该指令只能在文件中存在一次,如果有多个,则只执行最后一条。
该指令有三种格式:
CMD ["executable","param1","param2"]
CMD command param1 param2
当Dockerfile指定了ENTRYPOINT,那么使用下面的格式:
CMD ["param1","param2"]
其中:
ENTRYPOINT指定的是一个可执行的脚本或者程序的路径,该指定的脚本或者程序将会以param1和param2作为参数执行。
所以如果CMD指令使用上面的形式,那么Dockerfile中必须要有配套的ENTRYPOINT。
5)ENTRYPOINT (设置container启动时执行的操作)
设置指令:指定容器启动时执行的命令,可以多次设置,但是只有最后一个有效。
两种格式:
ENTRYPOINT ["executable", "param1", "param2"]
ENTRYPOINT command param1 param2
该指令的使用分为两种情况,一种是独自使用,另一种和CMD指令配合使用。
当独自使用时,如果你还使用了CMD命令且CMD是一个完整的可执行的命令,那么CMD指令和ENTRYPOINT会互相覆盖,只有最后一个CMD或者ENTRYPOINT有效。
# CMD指令将不会被执行,只有ENTRYPOINT指令被执行
CMD echo “Hello, World!”
ENTRYPOINT ls -l
另一种语法和CMD指令配合使用来指定ENTRYPOINT的默认参数,这时CMD指令不是一个完整的可执行命令,仅仅是参数部分;
ENTRYPOINT指令只能使用JSON方式指定执行命令,而不能指定参数。
FROM ubuntu
CMD ["-l"]
ENTRYPOINT ["/usr/bin/ls"]
6)USER(设置container容器的用户)
设置指令,设置启动容器的用户,默认是root用户。
# 指定memcached的运行用户
ENTRYPOINT ["memcached"]
USER daemon
或者
ENTRYPOINT ["memcached", "-u", "daemon"]
7)EXPOSE(指定容器需要映射到宿主机器的端口)
设置指令,该指令会将容器中的端口映射成宿主机器中的某个端口。当你需要访问容器的时候,可以不是用容器的IP地址,而是使用宿主机器的IP地址和映射后的端口。
要完成整个操作需要两个步骤,首先在Dockerfile使用EXPOSE设置需要映射的容器端口,然后再运行容器的时候指定-p选项加上EXPOSE设置的端口,这样EXPOSE设置的端口号会被随机映射成宿主机器中的一个端口号。
也可以指定需要映射到宿主机器的那个端口,这时要确保宿主机器上的端口号没有被使用。EXPOSE指令可以一次设置多个端口,相应的运行容器的时候,可以配套的多次使用-p选项
EXPOSE [...]
# 映射一个端口
EXPOSE port1
# 相应的运行容器使用的命令
docker run -p port1 image
# 映射多个端口
EXPOSE port1 port2 port3
# 相应的运行容器使用的命令
docker run -p port1 -p port2 -p port3 image
# 还可以指定需要映射到宿主机器上的某个端口号
docker run -p host_port1:port1 -p host_port2:port2 -p host_port3:port3 image
端口映射是docker比较重要的一个功能,原因在于我们每次运行容器的时候容器的IP地址不能指定而是在桥接网卡的地址范围内随机生成的。
宿主机器的IP地址是固定的,我们可以讲容器的端口的映射到宿主机器上的一个端口,免去每次访问容器中的某个服务时都要查看容器的IP的地址。
对于一个运行的容器,可以使用docker port加上容器中需要映射的端口和容器的ID来看该端口号在宿主机器上的映射端口。
8)ENV(用于设置环境变量)
主要用于设置容器运行时的环境变量
格式:
ENV
设置了后,后续的RUN命令都可以使用,container启动后,可以通过docker inspect查看这个环境变量,也可以通过在docker run --env key=value时设置或修改环境变量。
假如你安装了JAVA程序,需要设置JAVA_HOME,那么可以在Dockerfile中这样写:
ENV JAVA_HOME /path/to/java/dirent
9)ADD(从src复制文件到container的dest路径)
主要用于将宿主机中的文件添加到镜像中
构建指令,所有拷贝到container中的文件和文件夹权限为0755,uid和gid为0:如果是一个目录,那么会将该目录下的所有文件添加到container中,不包括目录:
如果文件是可识别的压缩格式,则docker会帮忙解压缩(注意压缩格式):如果是文件且中不使用斜杠结束,则会将视为文件,的内容会写入:
如果是文件且中使用斜杠结束,则会文件拷贝到目录下。
格式:
ADD
是相对被构建的源目录的相对路径,可以是文件或目录的路径,也可以是一个远程的文件url;
是container中的绝对路径
10)VOLUME(指定挂载点)
设置指定,使容器中的一个目录具有持久化存储数据的功能,该目录可以被容器本身使用,也可以共享给其他容器使用。我们知道容器使用的是AUFS,
这种文件系统不能持久化数据,当容器关闭后,所有的更改都会丢失。当容器中的应用有持久化数据的需求时可以在Dockerfile中使用该指令
格式:
VOLUME ["" ]
VOLUME ["/tmp/data"]
运行通过该Dockerfile生成image的容器,/tmp/data目录中的数据在容器关闭后,里面的数据还存在。例如另一个容器也有持久化数据的需求,且想使用上面容器共享的/tmp/data目录,那么可以运行下面的命令启动一个容器:
docker run -t -i -rm -volumes-from container1 image2 bash
其中:container1为第一个容器的ID,image2为第二个容器运行image的名字。
11)WORKDIR(切换目录)
设置指令,可以多次切换(相当于cd命令),对RUN,CMD,ENTRYPOINT生效。
格式:
WORKDIR /path/to/workdir
# 在/p1/p2下执行vim a.txt
WORKDIR /p1 WORKDIR p2 RUN vim a.txt
12)ONBUILD(在子镜像中执行)
格式:
ONBUILD
ONBUILD 指定的命令在构建镜像时并不执行,而是在它的子镜像中执行
dockerfile构建镜像:
步骤1:创建一个目录
mkdir rw-test
vim Dockerfile
编辑内容如下:
#pull down centos image
FROM docker.io/centos
MAINTAINER ruanwen onlien033_login@126.com
#install nginx
RUN yum install -y pcre pcre-devel openssl openssl-devel gcc gcc+ wget vim net-tools
RUN useradd www -M -s /sbin/nologin
RUN cd /usr/local/src && wget http://nginx.org/download/nginx-1.8.0.tar.gz && tar -zxvf nginx-1.8.0.tar.gz
RUN cd /usr/local/src/nginx-1.8.0 && ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_stub_status_module --with-http_ssl_module && make && make install
ENTRYPOINT /usr/local/nginx/sbin/nginx && tail -f /usr/local/nginx/logs/access.log
docker build -t rw_nginx --rm=true .
-t 表示选择指定生成镜像的用户名,仓库名和tag
--rm=true 表示指定在生成镜像过程中删除中间产生的临时容器
注意:上面构建命令中最后的.符合不要漏了,表示使用当前目录下的Dockerfile构建镜像
会依次运行Dockerfile文件的每一个步骤
步骤4:测试
docker run -ti -d --name test_nginx -p 8899:80 rw_nginx /bin/bash
docker exec test_nginx /bin/bash
#
通过浏览器访问:http://ip:8899
Docker仓库(Repository)类似与代码仓库,是Docker集中存放镜像文件的地方。
1,打开https://hub.docker.com/
2,注册账号,略
3,创建仓库(Create Repository):略
4,设置镜像标签
docker tag local-image:tagname new-repo:tagname
示例:docker tag hello-word:latest myqxin/test-hello-world:v1
5,登录docker hub
docker login(回车,输入账号和密码)
6,推送镜像
docker push new-repo:tagname
示例:docker push myqxin/test-hello-world:v1
我这里把test-hello-world弄成了test-hell-world,你们注意一下
略:参考官方文档
步骤:
1,创建阿里云账号
2,创建命令空间
3,创建镜像仓库
4,操作指南
$ sudo docker login --username=[账号名称] registry.cn-hangzhou.aliyuncs.com
$ sudo docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/360buy/portal:[镜像版本号]
$ sudo docker push registry.cn-hangzhou.aliyuncs.com/360buy/portal:[镜像版本号]
1,启动docker Registry,使用Docker官方提供的Registry镜像就可以搭建本地私有镜像仓库,具体指令如下。
docker run -d \
-p 5000:5000 \
--restart=always \
--name registry \
-v /mnt/registry:/var/lib/registry \
registry:2
指令参数说明:
-d:表示在后台运行该容器
-p 5000:5000:表示将私有镜像仓库容器内部默认暴露的5000端口映射到宿主机的5000端口
–restart=always:表示容器启动后自动启动本地私有镜像仓库
–name registry:表示为生成的容器命名为registry
-v /mnt/registry:/var/lib/registry:表示将容器内的默认存储位置/var/lib/registry中的数据挂载到宿主机的/mnt/registry目录下,这样当容器销毁后,在容器中/var/lib/registry目录下的数据会自动备份到宿主机指定目录
提示:
Docker Registry目前有v1和v2两个版本,v2版本并不是v1版本的简单升级,而是在很多功能上都有了改进和优化。v1版本使用的是Python开发的,而v2版本是用go语言开发的,v1版本本地镜像仓库容器中数据默认挂载点是/tmp/registry,而v2版本的本地镜像仓库容器中数据默认挂载点是/var/lib/registry
重命名镜像:之前推送镜像时,都是默认推送到远程镜像仓库,而本次是将指定镜像推送到本地私有镜像仓库。由于推送到本地私有镜像仓库的镜像名称必须符合“仓库IP:端口号/repository”的形式,因此需要按照要求修改镜像名称,具体操作指令如下。
docker tag hello-world:latest localhost:5000/myhellodocker
推送镜像:本地私有镜像仓库搭建并启动完成,同时要推送的镜像也已经准备就绪后,就可以将指定镜像推送到本地私有镜像仓库了,具体操作指令如下
docker push localhost:5000/myhellodocker
查看本地仓库镜像
http://localhost:5000/v2/myhellodocker/tags/list (注意:使用该地址时注意镜像名称)
由于做了目录挂载,因此可以在本地的该目录下查看:
/mnt/registry/docker/registry/v2/repositories
推送,不需要输入账号密码(不安全)
1,查看Docker Registry私有仓库搭建所在服务器地址:ipconfig
例如:服务器地址为:192.168.204.130
2,生成自签名证书(在home目录下执行上述指令后)
要确保Docker Registry本地镜像仓库的安全性,还需要一个安全认证证书,来保证其他Docker机器不能随意访问该机器上的Docker Registry本地镜像仓库,所以需要在搭建Docker Registry本地镜像仓库的Docker主机上先生成自签名证书(如果已购买证书就无需生成),具体操作指令如下:
mkdir registry && cd registry && mkdir certs && cd certs
openssl req -x509 -days 3650 -subj '/CN=192.168.204.130:5000/' \
-nodes -newkey rsa:2048 -keyout domain.key -out domain.crt
指令参数说明:
-x509:x509是一个自签发证书的格式
rsa:2048,是证书算法长度
domain.key和domain.crt:就是生成的证书文件
3,生成用户名和密码
在Docker Registry本地镜像仓库所在的Docker主机上生成自签名证书后,为了确保Docker机器与该Docker Registry本地镜像仓库的交互,还需要生成一个连接认证的用户名和密码,使其他Docker用户只有通过用户名和密码登录后才允许连接到Docker Registry本地镜像仓库
cd .. && mkdir auth
docker run --entrypoint htpasswd registry:2 -Bbn ruanwen 123456 > auth/htpasswd
4、启动Docker Registry本地镜像仓库服务(将之前创建的容器删除)
docker run -d \
-p 5000:5000 \
--restart=always \
--name registry \
-v /mnt/registry:/var/lib/registry \
-v `pwd`/auth:/auth \ -e "REGISTRY_AUTH=htpasswd" \
-e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
-e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd \
-v `pwd`/certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
registry:2
5、配置Docker Registry访问接
完成Docker Registry本地镜像仓库服务启动后,还需要在搭建了Docker Registry本地镜像仓库所在的Docker主机上配置供其他Docker机器访问的接口,具体指令如下:
sudo mkdir -p /etc/docker/certs.d/192.168.204.130:5000
sudo cp certs/domain.crt /etc/docker/certs.d/192.168.204.130:5000
6、Docker Registry私有仓库使用登记
在Docker机器终端使用sudo vim /etc/docker/daemon.json命令编辑daemon.json文件,在该文件中添加如下内容
{“insecure-registries”:[“192.168.200.162:5000”]}
7、重启并加载docker配置文件
sudo /etc/init.d/docker restart
二、验证测试1、装备镜像
docker tag hello-world:latest 192.168.200.162:5000/myhelloworld
2、推送镜像
docker push 192.168.200.141:5000/myhelloworld
送过程中出现错误,信息提示为:no basic auth credentials(即没有通过身份验证),所以无法进行推送,这也就说明身份验证的配置有效。要想成功推送,需要先登录成功后再推送
3、登录Docker Registry镜像仓库
docker login 192.168.200.162:5000
4、再次推送
docker push 192.168.200.139:5000/myhelloworld
5、结果验证