目录
# 制作空镜像 ~]# tar -cf - --files-from=/dev/null | docker import - scratch ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE scratch latest 130bf0c96118 19 seconds ago 0B
一.创建简单的镜像
1.自定义镜像原理
镜像采用分层设计
- 创建读写层
- 修改配置
- 重新打包
2.创建commit自定义镜像
- 使用现有镜像启动容器,在该容器基础上修改
- 使用commit制作新镜像
- docker commit 容器id 新镜像名称:标签
3.示例
# 创建一个底层容器 ~]# docker run -it centos:latest # 在容器里准备yum源并安装软件包(华为yum源) /]# rm -f /etc/yum.repos.d/*.repo /]# curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.myhuaweicloud.com/repo/CentOS-Base-7.repo /]# yum install -y net-tools vim-enhanced tree bash-completion iproute psmisc && yum clean all # 退出容器并打包这个容器成为新的镜像 /]# exit ~]# docker commit 02fd1719c038 myos:latest # 此时就是根据centos镜像做出了一个新的独立镜像 ]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE centos latest 5d0da3dc9764 3 months ago 231MB ~]# docker history centos IMAGE CREATED CREATED BY SIZE COMMENT 5d0da3dc9764 3 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B .....
二.用Dockerfile创建镜像
1.Dockerfile的概述
1)commit的局限
-很容易制作简单的镜像,但碰到复杂的情况就十分不方便,
例如:
-需要设置默认的启动命令
-需要设置环境变量(比如PATH)
-需要指定镜像开放某些特定的端口
dockerfile是一种更强大的镜像制作方式
-编写类似于脚本的Dockerfile文件,通过该文件制作镜像
2.Dockerfile语法
-FROM: 基础镜像 -MAINTAINER: 该指令用来设置镜像的维护者信息(AINTAINER 说明信息<邮箱地址>) -RUN: 制作镜像时执行的命令,可以有多个 -ADD: 复制文件到镜像,自动解压 -COPY: 复制文件到镜像,不解压 -EXPOSE: 声明开放的端口 -ENV: 设置容器启动后的环境变量 -WORKDIR: 定义容器默认工作目录(等于cd) -CMD: 容器启动时执行的命令, 仅可以有一条CMD
3.使用Dockerfile创建镜像
docker build 根据Dockerfile里的内容生成镜像
使用Dockerfile工作流程
-创建目录mkdir mybuild(文件名任意)
-在目录中编写Dockerfile
-生成镜像
~]# docker build -t 镜像名称:标签 Dockerfile所在目录 -t: 指定镜像名与标签 -f: 指定Dockerfile文件路径
4.示例
## 制作apache镜像 # 书写Dokcerfile,这里用commit制作的镜像作为底层镜像 ~]# mkdir web; cd web ~]# vim Dockerfile FROM myos:latest # commit制作的镜像作为底层镜像 RUN yum install -y httpd php # 由于底层镜像里有yum所以这里直接安装httpd与php(相等于远程执行命令) ENV LANG=C # locale可以查看到本机的操作系统语言,这里是防止出现乱码,所以设置为英文‘C’ ADD webhome.tar.gz /var/www/html/ # 类似于`docker cp` 随便找一个web页面的压缩包,拷贝到容器的httpd网页配置文件中 WORKDIR /var/www/html/ # 类似于cd,创建容器的时候直接以这个目录为首目录 EXPOSE 80 # 监听端口 CMD ["/usr/sbin/httpd", "-DFOREGROUND"] # 容器启动命令 ## 启动命令示例 # /bin/ls 则写成CMD ["/bin/ls"] # /bin/ls -l -a 则写成 CMD ["bin/ls","-l","-a"] #注:那么我们怎么知道启动命令呢;找服务启动文件 ~]# rpm -ql httpd | grep service /usr/lib/systemd/system/httpd.service ~]# cat /usr/lib/systemd/system/httpd.service ..... ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND ..... ~]# echo $OPTIONS # 此时发现echo为空,所以启动命令是/usr/sbin/httpd -DFOREGROUND(-DFOREGROUND为选项,写法如上) ## 随便找一个web页面拷贝到当前目录中(也就是写dockerfile文件的目录) # 开始制作镜像 ~]# docker build -t myos:httpd . # 查看与验证镜像 -t 镜像名于版本 -f 指定dockerfile文件 --network=host 使用宿主网络(因为容器默认的网络有些不可用) #查看镜像 ~]# docker images # 删除所有多余的镜像(方便测试) ~]# docker rm -f $(docker ps -aq) # 安装一个服务测试 ~]# docker run -itd myos:httpd ## 访问测试 # 先找到ip ~]# docker inspect 753ff4121bda "Networks": { ...... "IPAddress": "172.17.0.2", ...... ~]# curl http://172.17.0.2/info.php
三.制作Dockerfile复杂镜像
1.微服务架构
- 微服务架构是一种架构模式,它提倡将单一应用程序划分 成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。
- 微服务架构有别于更为传统的单体式方案,将应用拆分成 多个核心功能。可以单独构建和部署
- 微服务架构不只是应用核心功能间的这种松散耦合,它还 涉及如何进行服务间通信以应对不可避免的故障、满足未来的可扩展性并实现新的功能集成
2)优点
- 它解决了复杂性问题。它将单体应用分解为一组服务。虽然功能总量不变,但应用程序已被分解为可管理的模块或 服务,这种体系结构使得每个服务都可以独立开发、运行,降低了服务的耦合性更适合CI/CD
3)微服务的优点是:
- 高度可扩展、出色的弹性、易于部署、易于访问、更加开发
- 松耦合高内聚
4)如何构建微服务
-微服务的核心就是“拆”
- 如何拆分服务?
- 要想构建微服务就要理清各个服务之间的关系
- 保持服务的持续演进,使服务能够快速、低成本地被拆分和 合并,以快速响应业务的变化,持续迭代
- docker这种应用的管理模式正是微服务的思想, 每个容器 承载一个服务。一台计算机同时运行多个容器,从而就能 很轻松地模拟出复杂的微服务架构
2.示例
注:容器是否要配置环境变量屈决于配置文件是否有环境变量
# 示例,查看service文件(yum安装的默认就有) ~]# cat /usr/lib/systemd/system/chronyd.service ...... EnvironmentFile=-/etc/sysconfig/chronyd # 该文件就是环境配置文件 ExecStart=/usr/sbin/chronyd $OPTIONS ....... # 查看环境配置文件 ~]# cat /etc/sysconfig/chronyd OPTIONS="" # 可以看到chrony服务的启动变量是空,所以不要配置,如果有的话则要把变量改成参数 ## 制作php-fpm镜像 # 准备工作,创建目录与查看启动命令 ~]# mkdir php; cd php ~]# cat /usr/lib/systemd/system/php-fpm.service ..... ExecStart=/usr/sbin/php-fpm --nodaemonize ..... # 创建Dockerfile文件,根据commit所创建的基础镜像制作 ~]# vim Dockerfile FROM myos:latest RUN yum install -y php-fpm COPY www.conf /etc/php-fpm.d/www.conf EXPOSE 9000 WORKDIR /usr/local/nginx/html COPY info.php info.php CMD ["/usr/sbin/php-fpm", "--nodaemonize"] # 制作镜像 ~]# docker build -t myos:php-fpm . # 测试 ~]# docker run -it [镜像id] /bin/bash /]# ps -ef 或 ss -nulpt # 此时就可以查看到php的进程与端口,如果不能使用改命令则基础镜像内软件包安装不齐(包名:psmisc)
制作nginx镜像
-nginx一般采用编译安装,在容器内编译不容易拍错也不便于管理
Dockerfile 中ADD可以将一一个压缩包在容器内解压释放
利用这一-特性,我们可以在外部编译nginx, 并把编译好的文件打包,使用打包文件构建nginx 镜像服务
nginx进程默认在后台运行,可以使用参数daemon off;强制进程在前台运行
## 先制作nginx的配置 # 准备软件包(网址:http://nginx.org/download/) ~]# wget http://nginx.org/download/nginx-1.20.1.tar.gz # 安装依赖包 ~]# yum install -y gcc make pcre-devel openssl-devel # 创建用户,没有用户不能启动 ~]# useradd nginx # 解压下好的包并进入nginx目录 ~]# tar -zxvf nginx-1.20.1.tar.gz && cd nginx-1.20.1 # 编译安装 ~]# ./configure --prefix=/usr/local/nginx --user=nginx --group=nginx --with-http_ssl_module ~]# make && make install # 进入配置目录压缩编译好的nginx文件,再传几个文件用作测试(该文件是网页文件需自己找,如果没有,可以自己写两个html,php结尾的文件) ~]# cd /usr/local/ && cp /root/nginx.html /root/nginx.php ./ ~]# tar czf nginx.tar.gz nginx ## 制作Dockerfie # 创建目录和准备做好的nginx压缩包 ~]# mkdir /root/nginx ;cd /root/nginx ~]# cp /usr/local/nginx.tar.gz ./ # 书写dockerfile文件(用之前commit制作的基础镜像) ~]# vim Dockerfile FROM myos:latest RUN yum install -y pcre openssl && useradd nginx ADD nginx.tar.gz /usr/local/ EXPOSE 80 WORKDIR /usr/local/nginx/html CMD ["/usr/local/nginx/sbin/nginx", "-g", "daemon off;"] #注:如果直接/usr/local/nginx/sbin/nginx启动服务,进程是直接由上帝进程控制,(nginx启动会自动干掉父进程,成为孤儿进程,所以直接会在父进程下,然而容器里面父进程就是上帝进程,所以容器启动不了) # 制作容器 ~]# docker build -t myos:nginx . # 测试 ~]# doker images ~]# docker ps # 查看是有镜像与容器是否启动(up)
查看nginx启动官网
启动当前进程,而不杀掉父进程
3.访问容器服务
默认容器可以访问外网
●但外部网络的主机不可以访问容器内的资源
●容器每次创建IP地址都会改变;
●解决这个问题的最佳方法是端口绑定,
●容器可以与宿主机的端口进行绑定,
●从而把宿主机变成对应的服务,不用关心容器的IP地址
发布容器web服务
使用-p参数把容器端口和宿主机端口绑定,同一个宿主机端口只能绑定一个容器服务
-p [选项IP]:宿主机端口:容器端口(可以有多个) ~]# docker run -itd -p 80:80 myos:httpd # 此时在内网环境就可以直接访问宿主机的ip加端口就可以直接访问 ~]# curl http://127.0.0.1:80
对外发布服务
给绑定容器的那台服务器绑定一个公网IP
~]# docker run -itd -p 80:80 myos:httpd # 此时直接到浏览器公网访问 ~]# http://(公网ip):80
再起一个nginx,如果要用80访问web服务,首先必须停止 apache
~]# docker ps -a| grep httpd ~]# docker stop (httpd容器的ID) ~]# docker run -itd -p 80:80 -p 9000:9000 myos:nginx # -p可以写多个
验证方式: 通过浏览器访问公网ip即可
四.容器共享卷
1.共享卷的用途
- Docker容器不适合保存任何数据
- 数据文件与配置文件频繁更改
- 修改多个容器中的数据非常困难多
- 容器之间有数据共享、同步需求
- 重要数据在容器内不方便管理易丢失
- 解决这些问题请使用主机卷映射功能
2.主机卷的映射
Docker可以映射宿主机文件或目录到容器中
- 目标对象不存在就自动创建
- 目标对象存在就直接覆盖掉
- 多个容器可以映射同一个目标对象来达到数据共享的目的# linux的映射 ~]# mount --bind /root/php /mnt/ ~]# umount /mnt
启动容器时,使用-v映射参数(可有多个)
docker run -itd -v 宿主机对象:容器内对象myos:latest
3.示例
# 创建映射目录{网页目录与配置文件} ~]# mkdir -p /var/{webroot,webconf} # 准备访问页面与配置文件 ~]# cp info.php info.html /var/webroot/ ~]# cp /usr/local/nginx/conf/nginx.conf /var/webconf/ # 修改配置文件启动php ~]# vim /var/webconf/nginx.conf ...... location ~ \.php$ { root html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi.conf; } ...... ~]# docker run -itd -p 80:80 --name nginx \ -v /var/webconf/nginx.conf:/usr/local/nginx/conf/nginx.conf -v /var/webroot:/usr/local/nginx/html myos:nginx #验证方式: 使用 exec 进入容器查看 ~]# docker exec -it nginx /bin/bash html]# cat /usr/local/nginx/conf/nginx.conf # 查看 php 相关配置是否被映射到容器内 # 报错处理 ~]# docker logs [容器ID]
五.容器间的网络通信
1.容器的网络通信模式
-host 模式,与宿主机共享网络 -container 模式,共享其他容器的网络命名空间 -none模式,无网络模式 -bridge模式,默认模式 -自定义网络,自由创建桥接网络或者overlay网络 # 注:共享网卡之后容器之间就可以访问了 --network=container:[要共享的容器名] # 示例 ~]# docker ..... --net host ... 镜像
2.示例
启动前端 nginx 服务,并映射共享目录和配置文件
# 创建共享目录{网页目录与配置文件} ~]# mkdir -p /var/{webroot,webconf} # 准备访问页面与配置文件(测试用的,随便整两个) ~]# cp info.php info.html /var/webroot/ [root@docker-0001 ~]# cp /usr/local/nginx/conf/nginx.conf /var/webconf/ # 修改配置文件 [root@docker-0001 ~]# vim /var/webconf/nginx.conf ....... location ~ \.php$ { root html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fastcgi.conf; } ....... # 启动前端 nginx 服务,并映射共享目录和配置文件 ~]# docker run -itd --name nginx -p 80:80 \ -v /var/webconf/nginx.conf:/usr/local/nginx/conf/nginx.conf \ -v /var/webroot:/usr/local/nginx/html myos:nginx # 启动后端 php 服务,并映射共享网页目录 ~]# docker run -itd --network=container:nginx -v /var/webroot:/usr/local/nginx/html myos:php-fpm # 验证服务 ~]# curl http://宿主ip/info.html ~]# curl http://宿主ip/info.php # 概述,先创建一个容器并配置名字;然后再创建一个容器,在创建时指定共享网络,共享网络指定上一个容器的名字
六.私有镜像仓库
1.镜像仓库的概述
镜像仓库作为Docker技术的核心组件之一,其主要作用就是负责镜像内容的存储和分发。Docker镜像仓库从使用范围来说分为“公有镜像仓库”和“私有镜像仓库”,公有镜像仓库是可以被任何人使用的,例如Docker公司维护的在线存储库Docker Hub以及部分云服务厂商(如阿里云)提供的在线Docker镜像库等,都属于公有镜像仓库的范畴。
而私有镜像仓库则是指部署在公司或组织内部,用于自身应用Docker镜像存储、分发的镜像仓库。在构建公司内部使用的自动化发布系统的过程中,从安全的角度出发,应用的打包镜像一般情况下只会被存储在私有镜像仓库中,CI/CD流程的衔接点也是通过向私有镜像仓库上传镜像和拉取镜像的操作来完成的。
在现阶段主流的企业级私有镜像仓库构建方案中,比较流行的是:开源的企业级Docker镜像仓库——Harbor、以及商业镜像仓库——JFrog Artifactory。这两种Docker镜像仓库各自都有一定的市场,就作者所工作过的公司来说使用Harbor和JFrog Artifactory作为私有镜像仓库的都有,但就成熟度和功能性完整性来说JFrog Artifactory作为商业级解决方案会更具优势,所以目前国内有钱的互联网公司选择JFrog Artifactory作为企业级私有仓库的比较多,本文的主要内容是演示如何通过Docker的方式来快速部署JFrog Artifactory并将其作为Devops自动发布系统的私有镜像仓库。
注:如果不配置仓库,那么每台docker只能查看与运用本机的镜像
仓库配置文件及镜像存储路径
/etc/docker-distribution/registry/config.yml
/var/lib/registry
默认端口号5000
我们可以通过curl命令访问仓库
# 镜像名称访问(查看仓库里的镜像名) ~]# curl http://仓库ip:5000/v2/_catalog # 标签访问(查看该镜像的所有标签) ~]# curl http://仓库ip:5000/v2/镜像名称/tags/list # v2是api的参数,用的是版本二的意思 # 镜像是由镜像的名称与镜像的标签组成;所以这两个访问方式分别访问名称与标签
2.搭建私有仓库
1)服务端配置
# 准备一台服务器,并安装服务仓库服务,启动并设置开启自启 ~]# yum install -y docker-distribution ~]# systemctl enable --now docker-distribution # 访问测试 ~]# curl http://192.168.1.100:5000/v2/_catalog {"repositories":[]}
2)docker客户端配置
如何让Docker知道私有仓库的地址
配置文件/etc/docker/damon.json
- cgroup 驱动,docker默认 cgroupfs
"exec-opts": ["native.cgroupdriver=systemd"]
- 默认下载仓库(使用国内源能快一点)
"registry-mirrors": ["https://hub-mirror.c.163.com"]
- 私有仓库地址(重点)(:”声明了主机ip“,“主机名”)
"insecure-registries":["192.168.1.100:5000", "registry:5000"]
3)配置示例
所有node节点都需要配置
~]# vim /etc/docker/daemon.json { "exec-opts": ["native.cgroupdriver=systemd"], "registry-mirrors": ["https://hub-mirror.c.163.com"], "insecure-registries":["192.168.1.100:5000", "registry:5000"] } # 重启服务生效 ~]# systemctl restart docker
3.使用镜像仓库
1)上传镜像
上传 myos:latest, myos:httpd, myos:nginx, myos:php-fpm
# 由于可能会由很多个仓库,所以必须打上标签标记;此时如果有一个域名,可以让这个域名来解析这个ip,那么这里的ip就可以用域名代替 ~]# docker tag myos:latest 192.168.1.100:5000/myos:latest ~]# docker push 192.168.1.100:5000/myos:latest # 前面这一段就是声明镜像仓库名(192.168.1.100:5000) ## 验证测试 # 查看镜像名 curl http://仓库IP:5000/v2/_catalog ~]# curl http://192.168.1.100:5000/v2/_catalog {"repositories":["myos"]} # 查看标签 curl http://仓库IP:5000/v2/镜像名称/tags/list ~]# curl http://192.168.1.100:5000/v2/myos/tags/list {"name":"myos","tags":["latest"]}
2)下载镜像
第一种方法
## 使用远程镜像启动容器 # 先查看有哪些镜像 ~]# curl http://192.168.1.100:5000/v2/_catalog ~]# curl http://192.168.1.100:5000/v2/myos/tags/list # 拉取镜像(前面是镜像仓库名192.168.1.100:5000/) ~]# docker pull 192.168.1.100:5000/myos:latest Unable to find image '192.168.1.100:5000/myos:latest' locally latest: Pulling from myos 7dc0dca2b151: Pull complete 95c297b4d705: Pull complete Digest: sha256:d61ffc053895e2dc16f63b8a2988dfe5f34207b48b1e74d397bb3267650ba4ce Status: Downloaded newer image for 192.168.1.100:5000/myos:latest # 查看 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE 192.168.1.100:5000/myos latest 8d17db982b34 3 days ago 281MB # 此时就可以查看到镜像,然后再启动容器,但是这样的话步骤太繁琐,所以还有一种方法
第二种方法
## 可以直接run启动时直接拉取仓库镜像 ~]# docker run -itd -p 80:80 192.168.1.100:5000/myos:latest # 查看容器是否启动 ~]# docker ps -a ONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a36f00980554 192.168.1.100:5000/myos "/usr/sbin/http -DF.." 3 days ago Up 3 days 0.0.0.0:80->80/tcp registry-http