需要使用红帽7.5版本以上的镜像构建的虚拟机
阿里云开源镜像站:https://mirrors.aliyun.com/docker-ce/linux/centos/7/x86_64/stable/Packages/
官方站点:https://docs.docker.com/ https://docs.docker.com/install/linux/docker-ce/centos/
安装
yum install bash-* -y
yum install *.rpm
安装完docker后如果 发现tab命令不能补全 是因为缺少一个包 yum install bash-* -y
安装一个小游戏
docker load -i game2048.tar
docker run -d --name game1 -p 80:80 game2048
docker ps
在浏览器中测试:ip地址 eg:网页游戏
解决“警告”问题:
docker info
可以看到
WARNING: IPv4 forwarding is disabled
WARNING: bridge-nf-call-iptables is disabled
WARNING: bridge-nf-call-ip6tables is disabled
cd /etc/sysctl.d
过滤内核参数 将这些改成 1
sysctl -a | grep forwarding
sysctl -a | grep bridge
cd /etc/sysctl.d/
vim docker.conf
inet.bridge.bridge-nf-call-ip6tables = 1
net.bridge.bridge-nf-call-iptables = 1
net.ipv4.conf.all.forwarding = 1
net.ipv4.conf.all.mc_forwarding = 1
net.ipv4.conf.default.forwarding = 1
net.ipv4.conf.default.mc_forwarding = 1
net.ipv4.conf.docker0.forwarding = 1
net.ipv4.conf.docker0.mc_forwarding = 1
net.ipv4.conf.eth0.forwarding = 1
net.ipv4.conf.eth0.mc_forwarding = 1
net.ipv4.conf.lo.forwarding = 1
net.ipv4.conf.lo.mc_forwarding = 1
net.bridge.bridge-nf-call-ip6tables = 1
sysctl --system #使其立即生效
docker命令 | |
---|---|
docker load -i ubuntu.tar | 导入镜像(以ubuntu镜像为模板) |
docker run -it --name vm1 ubuntu | 创建容器(以ubuntu镜像为模板) |
docker ps | 查看容器状态,当前活跃的 |
docker ps -a | 查看容器状态(包括不活跃的容器),所有的 |
docker attach vm1 | 连接容器 |
docker top vm1 | 查看容器进程 |
docker logs vm1 | 查看容器指令输出 -f 参数可以实时查看 |
docker inspect vm1 | 查看容器详情 |
docker stats vm1 | 查看容器资源使用率 |
docker diff vm1 | 查看容器修改 |
docker stop vm1 | 停止容器 |
docker start vm1 | 启动容器 |
docker kill vm1 | 强制干掉容器 |
docker restart vm1 | 重启容器 |
docker pause/unpause vm1 | 暂停/恢复容器 |
docker rm vm1 | 删除容器 |
docker rm -f vm1 | 强制删除容器 |
docker rmi ubantu | 删除镜像 |
docker images | 列出镜像 |
docker run 参数 | |
---|---|
-a stdin | 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项; |
-d | 后台运行容器,并返回容器ID; |
-i | 以交互模式运行容器,通常与 -t 同时使用; |
-P | 随机端口映射,容器内部端口随机映射到主机的端口 |
-p | 指定端口映射,格式为:主机(宿主)端口:容器端口 |
-t | 为容器重新分配一个伪输入终端,通常与 -i 同时使用; |
–name=“nginx-lb” | 为容器指定一个名称; |
–dns 8.8.8.8 | 指定容器使用的DNS服务器,默认和宿主一致; |
–dns-search example.com | 指定容器DNS搜索域名,默认和宿主一致; |
-h “mars” | 指定容器的hostname; |
-e username=“ritchie” | 设置环境变量; |
–env-file=[] | 从指定文件读入环境变量; |
–cpuset=“0-2” or --cpuset=“0,1,2” | 绑定容器到指定CPU运行; |
-m | 设置容器使用内存最大值; |
–net=“bridge” | 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型; |
–link=[] | 添加链接到另一个容器; |
–expose=[] | 开放一个端口或一组端口; |
–volume , -v | 绑定一个卷 |
镜像是一种文件结构,包含如何运行容器的元数据 Dockerfile中的每条命令都会在文件系统中创建一个新的层次结构
文件系统在这些层次上构建起来,镜像就构建于这些联合的文件系统之上 当容器启动后,所有镜像都会统一合并到一个进程中
联合文件系统中的文件被删除时, 它们只是被标记为已删除,但实际上仍然存在
镜像是docker容器的基石,容器是镜像的运行实例,有了镜像才能启动容器
docker images rhel7
docker run -it --name vm1 ubuntu #run:创建并运行一个容器
-it:以交互式的形式 --name:给容器起个名字 ubuntu:镜像名称
docker ps -a 查看镜像
docker rm b16f9eaab99e 删除镜像,后面加镜像ID
运行容器
修改容器
将容器保存为新的镜像
缺点
效率低 可重复性弱 容易出错 使
用者无法对镜像进行审计,存在安全隐患
docker images
docker history ubuntu:latest # 保存每一层的镜像修改
的意思是 这些操作不是在本机操作的 所有找不到 这并没有什么关系
docker run -it --name test busybox
echo helloworld >testfile
ls
cat testfile
helloworld
exit #退出并停止运行 ctrl p+q 退出不停止运行
docker ps -a #注意:我们只是退出了运行中的容器 并没有删除它
docker start test #我们将在后台保存的容器运行起来
docker attach test #此命令可以进入在后台运行起来的容器
docker commit test test:v1 #将我们所修改的容器保存
docker images
docker history test:v1 #我们可以看到 相同的底层是共享的
docker rm 6789012d8958 可以强制删除正在运行中的容器
缺点是:无法得知对这个容器到底做了什么操作 虽然它已经被保存了,新运行的容器也有之前所保存的数据
dockerfile语法
FROM | 每个Dockerfile的第一条指令都应该是FROM。FROM指令指定一个已经存在的镜像,后续指令都是将基于该镜像进行,这个镜像被称为基础镜像(base iamge)。在这里ubuntu:latest就是作为新镜像的基础镜像。也就是说Dockerfile构建的新镜像将以ubuntu:latest操作系统为基础。在运行一个容器时,必须要指明是基于哪个基础镜像在进行构建。 |
MAINTAINER | MAINTAINER指令,这条指令会告诉Docker该镜像的作者是谁,以及作者的邮箱地址。这有助于表示镜像的所有者和联系方式 |
RUN | 在这些命令之后,RUN指令会在当前镜像中运行指定的命令。这里我们通过RUN指令更新了APT仓库,安装nginx包,并创建了一个index.html文件。像前面说的那样,每条RUN指令都会创建一个新的镜像层,如果该指令执行成功,就会将此镜像层提交,之后继续执行Dockerfile中的下一个指令。默认情况下,RUN指令会在shell里使用命令包装器/bin/sh -c 来执行。如果是在一个不支持shell的平台上运行或者不希望在shell中运行(比如避免shell字符串篡改),也可以使用exec格式的RUN指令,通过一个数组的方式指定要运行的命令和传递给该命令的每个参数:RUN [“apt-get”, “install”, “-y”, “nginx”] |
EXPOSE | EXPOSE指令是告诉Docker该容器内的应用程序将会使用容器的指定端口。这并不意味着可以自动访问任意容器运行中服务的端口。出于安全的原因,Docker并不会自动打开该端口,而是需要你在使用docker run运行容器时来指定需要打开哪些端口。可以指定多个EXPOSE指令来向外部公开多个端口,Docker也使用EXPOSE指令来帮助将多个容器链接。 |
COPY | 把文件从build context复制到镜像,支持两种形式:COPY src dest 和 COPY [“src”, “dest”],src必须指定build context中的文件或目录 |
ADD | 用法与COPY类似,不同的是src可以是归档压缩文件,文件会被自动解压到dest,也可以自动下载URL并拷贝到镜像:ADD html.tar /var/www |
ENV | 设置环境变量,变量可以被后续的指令使用:ENV HOSTNAME sevrer1.example.com |
WORKDIR | 为RUN、CMD、ENTRYPOINT、ADD和COPY指令设置镜像中的当前工作目录,如果目录不存在会自动创建。 |
CMD | 与 ENTRYPOIN 这两个指令都是用于设置容器启动后执行的命令,但CMD会被docker run后面的命令行覆盖,而ENTRYPOINT不会被忽略,一定会被执行。docker run后面的参数可以传递给ENTRYPOINT指令当作参数。Dockerfile中只能指定一个ENTRYPOINT,如果指定了很多,只有最后一个有效。 |
注意:一定要创建一个新的目录 因为在构建镜像的时候,会默认把dockerfile所在的目录中的所有目录发送给docker引擎,举个例子
如果你把dockerfile放在/目录下 那么这个过程会变得非常的缓慢
vim dockerfile
FROM busybox #以哪个基础镜像为模板
RUN echo testfile > file1 #在新镜像中你要执行的哪些动作
RUN echo testfile > file2
docker build -t test:v2 #镜像名称 . #.代表当前目录
docker images
docker history test:v2
再次更改dockerfile 注意:不要随便加空格(要使用缓存 之前内容不能随便更改)
如果我们希望在构建镜像时不使用缓存,可以在docker build命令中加上 --no-cache参数
dockerfile中每一个指令都会创建一个镜像层,上层是依赖于下层的,无论什么时候,只要某一层发生变化, 其上面所有层的缓存都会失败
本质:dockerfile中的每一层其实就是执行了一个docker commit
选择最经简的基础镜像
减少镜像的层数
清理镜像构建的中间产物
注意优化网络请求
尽量去构建缓存
使用多阶段构建镜像
前提:保证镜像存在于本地
编写dockerfile
cat dockerfile
FROM rhel7
EXPOSE 80
MAINTAINER dd@westos.org
COPY dvd.repo /etc/yum.repos.d/
RUN rpmdb --rebuilddb
RUN yum install -y gcc make pcre-devel zlib-devel
ADD nginx-1.15.9.tar.gz /mnt
WORKDIR /mnt/nginx-1.15.9
RUN ./configure --prefix=/usr/local/nginx
RUN make
RUN make install
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
其中
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"] 通过exec的方式启动nginx
RUN rpmdb --rebuilddb #重新构建rpm数据库 如不执行这一条命令 会报错 #上课示例的时候可以先不加这一句
docker build -t nginx:v1 .
查看镜像大小
减少镜像层数------合并多个RUN
删除解压目录------减少中间产物
注意:修改了指令 哪怕是一个空格 缓存就不能用了 。
使用缓存可以加快镜像构建速度
vimdockerfile
FROM rhel7
EXPOSE 80
MAINTAINER dd@westos.org
COPY dvd.repo /etc/yum.repos.d/
ADD nginx-1.15.9.tar.gz /mnt
WORKDIR /mnt/nginx-1.15.9
RUN rpmdb --rebuilddb && yum install -y gcc make pcre-devel zlib-devel && yum clean all && ./configure --prefix=/usr/local/nginx && make && make install && rm -rf /mnt/nginx-1.15.9
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
docker build -t nginx:v2 .
docker images
使用多阶段构建镜像
细看dockerfile 我们其实只需要编译好的nginx的二进制文件
vimdockerfile
FROM rhel7:latest as build
EXPOSE 80
MAINTAINER dd@westos.org
COPY dvd.repo /etc/yum.repos.d/
ADD nginx-1.15.9.tar.gz /mnt
WORKDIR /mnt/nginx-1.15.9
RUN rpmdb --rebuilddb && yum install -y gcc make pcre-devel zlib-devel && yum clean all && ./configure --prefix=/usr/local/nginx && make && make install && rm -rf /mnt/nginx-1.15.9
####以上只是一个桥梁
FROM rhel7:latest #基于rhel7的基础镜像
EXPOSE 80
MAINTAINER dd@westos.org
VOLUME ["/usr/local/nginx/html"]
COPY --from=build /usr/local/nginx /usr/local/nginx #从上一层的构建中拷贝
CMD ["/usr/local/nginx/sbin/nginx","-g","daemon off;"]
docker build -t nginx:v4 .
docker images
启动容器的方法
docker run ubuntu pwd
docker run ubuntu ls
容器长期运行
因为容器的生命周期依赖于启动时执行的命令,只要该命令不结束,容器也就不会退出
docker run ubuntu /bin/bash -c 'while true;do sleep 1;done'
#while语句让bash不会退出,可以打开另一个终端查看容器的状态
通过while启动的容器虽然能够保持运行,但实际上没有干什么有意义的事情,容器常见的用途是运行后台服务
docker run --name "my_http_server" -d httpd 指定容器的名字
我们经常需要进入到容器里去做一些工作,比如查看日志,调式,启动其他进程等,有两种方法进入容器:
attach
通过docker attach可以attach到容器启动命令的终端
docker attach 039c0b492b5da9301d576b0d7db269545d0289cf31f5706d575e708258b20502
exec
docker run -d rhel7-up /bin/bash -c "while true; do sleep1;echo I_am_in_container;done"
docker exec -it c72e8ee26615ca661093d6114c0dbb143e50ef423382730d0f3d8a92d01b2e0c bash
yum install procps-ng-3.3.10-10.el7.x86_64 -y
ps -elf
attach与exec主要的区别
1.attach直接进入容器启动命令的终端,不会启动新的进程
2.exec则是在容器中打开新的终端,并且可以启动新的进程
3.如果想直接在终端中查看启动命令的输入,用attach,其他情况使用exec
按用途容器大致可分为两类:服务类容器和工具类容器 服务类容器以daemon的形式运行,对外提供服务,比如web server,数据库等,通过-d以后台方式启动这类容器是非常合适的,如果要排查问题,可以通过exec -it进入容器
工具类容器通常能给我们提供一个临时的工作环境,通常以run -it方式运行
仓库的概念
docker仓库是用来保存镜像的位置,docker提供一个注册服务器(register)来保存多个仓库,每个仓库又可以包含多个具备不同的tag的镜像
docker运行中使用的默认仓库是docker Hub 公共仓库 docker hub:是docker公司维护的公共仓库,用户可以免费使用,也可以购买私有仓库 使用公共registry
保存和分发镜像的最直接的方法就是使用DockerHub
在docker hub上注册一个帐号
登陆
docker login -u dangdangwestos
Password: #密码:dangdang
cat .docker/config.json #做过一个认证后就把认证信息放在文件中
修改镜像的名字 使之与Docker Hub帐号匹配
docker hub为了区分不同用户的镜像名 镜像的名字中要包含用户名
完整格式为[username]/xxx:tag
镜像的上传和拉取
docker search busybox搜寻docker官方仓库中的镜像
docker tag busybox:latest dangdangwestos/busybox:latest 打标签
docker push dangdangwestos/busybox:latest 上传
docker pull dangdangwestos/busybox:latest 拉取 会先检索本地的镜像 如果存在则不会被拉取,如果有,先删除之前的再拉取
docker tag dangdangwestos/busybox:latest busybox:latest 再次打标签简化镜像名称
删除docker hub上的镜像
用户发送请求到index来下载镜像。
index 响应返回三个相关部分信息:该镜像位于的registry+该镜像包括所有层的校验+以授权目的Token
用户通过响应中返回的Token和registry沟通,registry全权负责镜像,它存储基本的镜像和继承的层。
registry现在要与index证实该token是被授权的。
index会发送“true” 或者 “false”给registry,由此允许用户下载所需要的镜像。
用户要上传镜像到registry中
用户发送带证书请求到index要求分配库名。
在成功认证,命名空间可用以及库名被分配之后。index响应返回临时的token。
镜像连带token,一起被推送到registry中。
registry与index证实token,然后在index验证之后开始读取推送流。
该index然后更新由Docker生成的镜像校验。
index接收来自Docker一个删除库的信号。
如果index验证库成功,它将删除该库,并返回一个临时token。
registry现在接收到带有该token的删除信号。
registry与index核实该token,然后删除库以及所有相关信息。
Docker现在通知有关删除的index,然后index移除库的所有记录。
docker hub虽然方便 但还是有些限制,
1.需要连接internet,下载和上传速度慢
2.上传到docker hub的镜像任何人都能访问
3.因安全原因很多组织不允许将镜像放到外网
解决方案就是搭建本地的registry docker已经将registry开源了,同时在docker hub上也有官方的镜像registry
拉取仓库的镜像运行
docker search registry
docker pull registry #拉取最新版
docker images
docker history registry
docker run -d --name registry -p 5000:5000 registry #端口映射到本机 便于外部访问
docker inspect 查看镜像信息
docker ps
netstat -antlpe 查看端口是否开启
上传,查看本地仓库的挂载目录
docker tag nginx:v1 localhost:5000/nginx:v1
docker push localhost:5000/nginx
docker inspect 查看镜像信息
cd /var/lib/docker/volumes/37e8aed215b0812c9ca3f3b6018a52bec0029844a2cd7dd4a505a6772fbc7e52/_data/docker/registry/
tree .
以上操作有安全问题(没有认证)和使用的问题(localhost 如果不是本机就使用不了localhost)
作为企业级的私有仓库是远远不够的
官方文档
https://docs.docker.com/registry/insecure/
生成一个自签名证书
mkdir -p certs
openssl req \
> -newkey rsa:4096 -nodes -sha256 -keyout certs/westos.org.key \
> -x509 -days 365 -out certs/westos.org.crt
-----
Country Name (2 letter code) [XX]:CN
State or Province Name (full name) []:Shaanxi
Locality Name (eg, city) [Default City]:Xi'an
Organization Name (eg, company) [Default Company Ltd]:Westos
Organizational Unit Name (eg, section) []:Linux
Common Name (eg, your name or your server's hostname) []:westos.org
Email Address []:root@westos.org
ls certs/
重新搭建私有仓库
https://docs.docker.com/registry/deploying/#get-a-certificate
注意此处:REGISTRY_HTTP_TLS_KEY=/certs/westos.org.key -p 443:443 registry
不是:/root/
docker rm -f registry 删除之前运行的registry容器
docker run -d --restart=always --name registry #容器自启动(docker引擎启动的同时会启动容器)
-v "$(pwd)"/certs:/certs #本地的certs目录挂接到容器的certs目录
-e REGISTRY_HTTP_ADDR=0.0.0.0:443 #-e 编辑 监听本机443的加密端口
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/westos.org.crt #证书
-e REGISTRY_HTTP_TLS_KEY=/certs/westos.org.key #私钥
-p 443:443 registry
netstat -antlp 开启了443端口
注意:此时 docker的server端已经跑起来了 那么们的本地要去做Tls连接的话也是需要加密证书的
因为我们所使用的域名是westos.org 所以主机名要有解析
ping westos.org
cd /etc/docker/
mkdir -p certs.d/westos.org
cd certs.d/westos.org
cp /root/certs/westos.org.crt ca.crt
docker tag nginx:v3 westos.org/nginx:v3
docker push westos.org/nginx
在之前的443更改 不用官网的5000 , 之前的registry要删除
mkdir ~/auth
docker run --rm entrypoint htpasswd registry -Bbn admin westos >auth/htpasswd
docker run --rm entrypoint htpasswd registry -Bbn redhat redhat >>auth/htpasswd 多个用户名可追加
docker rm -f registry
在加密的基础上做认证
一定是先加密再认证 要不是不安全的
docker run -d --restart=always --name registry -v "$(pwd)"/certs:/certs -e REGISTRY_HTTP_ADDR=0.0.0.0:443 -e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/westos.org.crt -e REGISTRY_HTTP_TLS_KEY=/certs/westos.org.key -p 443:443 -v "$(pwd)"/auth:/auth -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd registry
docker ps -a
docker login westos.org
Username: admin
Password:
docker logout westos.org #退出登陆
push提示报错:Removing login credentials for westos.org
docker push westos.org/nginx
docker login westos.org
docker push westos.org/nginx:v3
no basic auth credentials 提示我们没有认证
docker login westos.org 重新登录
docker push westos.org/nginx:v3
准备另一台虚拟机,安装docker并启动 ,主机名要有解析
要有认证文件,这个文件可以从上一台主机获得 现有证书才能完成认证
scp -r certs.d/ server2:/etc/docker/
docker login westos.org 先认证再拉取
docker pull westos.org/nginx:v3
docker run -d --name nginx -p 80:80 westos.org/nginx:v3 测试运行
docker ps
curl localhost
拉取web镜像
去git hub搜索 按照文档做操作 https://github.com/mkuchin/docker-registry-web
docker pull hyper/docker-registry-web
cat .docker/config.json 查看之前的认证信息
docker run -it -p 8080:8080 --name registry-web --link registry:westos.org -e REGISTRY_URL=https://westos.org/v2 -e REGISTRY_TRUST_ANY_SSL=true -e REGISTRY_BASIC_AUTH="YWRtaW46d2VzdG9z" -e REGISTRY_NAME=westos.org:443 hyper/docker-registry-web #v2:是一个版本
http://172.25.0.3:8080/
推荐学习:https://goharbor.io/ https://docs.docker.com/compose/install/
下载,授予执行权限
curl -L "https://github.com/docker/compose/releases/download/1.24.1/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
docker-compose --version
tar zxf harbor-online-installer-v1.8.2.tgz
cd harbor/
修改配置文件
vim harbor.yml
hostname: westos.org
13 https:
14 # # https port for harbor, default is 443
15 port: 443
16 # # The path of cert and key files for nginx
17 certificate: /root/certs/westos.org.crt
18 private_key: /root/certs/westos.org.key
27 harbor_admin_password: westos
28
29 # Harbor DB configuration
30 database:
31 # The password for the root user of Harbor DB. Change this be fore any production use.
32 password: westos
./prepare 更新配置文件
./install.sh
docker ps -a
docker-compose ps
docker login westos.org
docker tag rhel7:latest westos.org/library/rhel7
在真机做好解析,浏览器中访问https://westos.org/
这里一定要注意的是:tag的修改 必须加项目名称 而这个项目名称可以自己在网页中创建 docker push westos.org/library/rhel7