mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255
... ...
[root@14b669a75a95 html]# vim /usr/local/nginx/conf/nginx.conf
32: listen 80
[root@14b669a75a95 html]# exit
```
cp从容器内拷贝文件出来--关于容器一定是决定路径
```bash
[root@docker ~]# docker cp web1:/usr/local/nginx/conf ./
Successfully copied 45.6kB to /root/./
```
重启容器---会报错,容器起不来
```
[root@docker ~]# docker restart web1
web1
[root@docker ~]# docker ps -a
14b669a75a95 myos:nginx ... ... Exited (1) web1
```
log查看日志拍错
```bash
[root@docker ~]# docker logs web1
nginx: [emerg] invalid parameter "server_name" in /usr/local/nginx/conf/nginx.conf:33
```
修复配置文件错误
---修改从容器拷贝过来的配置文件(自行拷贝)
```bash
[root@docker ~]# vim conf/nginx.conf
32: listen 80;
```
```bash
[root@docker ~]# docker cp conf/nginx.conf web1:/usr/local/nginx/conf/nginx.conf
Successfully copied 4.61kB to web1:/usr/local/nginx/conf/nginx.conf
```
```
[root@docker ~]# docker restart web1
web1
[root@docker ~]# docker ps
CONTAINER ID IMAGE ... ... STATUS PORTS NAMES
14b669a75a95 myos:nginx ... ... Up 2 seconds 80/tc
```
#### 简单镜像制作

使用基础镜像创建一个容器
```bash
[root@docker ~]# docker run -itd --name linux rockylinux:8.5
```
删除容器内的Yum配置文件
```bash
[root@docker ~]# docker exec -it linux rm -rf /etc/yum.repos.d
```
拷贝宿主机的Yum配置文件到容器内
```
[root@docker ~]# docker cp /etc/yum.repos.d linux:/etc/
```
在容器内安装工具软件包
```bash
[root@docker ~]# docker exec -it linux dnf install -y net-tools vim-enhanced tree bash-completion iproute procps-ng psmisc
```
清理缓存文件
```
[root@docker ~]# docker exec -it linux dnf clean all
```
停止容器
```
[root@docker ~]# docker stop linux
```
把容器制作成镜像
```bash
[root@docker ~]# docker commit linux mylinux:latest
```
查看新制作的镜像
```bash
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
mylinux latest b64da40467ae 3 seconds ago 249MB
rockylinux 8.5 210996f98b85 13 months ago 205MB
```
删除制作镜像的容器
```bash
[root@docker ~]# docker rm -f linux
linux
```
##### 容器部署应用
- 部署 apache 服务
删除所有容器
```bash
[root@docker ~]# docker rm -f $(docker ps -aq)
```
创建一个名为 myweb 的容器
```bash
[root@docker ~]# docker run -it --rm --name myweb mylinux:latest
```
在容器内安装部署 apache
```bash
[root@a7f9d0c3e3e2 /]# dnf install -y httpd
[root@a7f9d0c3e3e2 /]# echo "Hello World ." >/var/www/html/index.html
[root@a7f9d0c3e3e2 /]# cat /usr/lib/systemd/system/httpd.service
#设置环境变量
[root@a7f9d0c3e3e2 /]# export LANG=C
#在前端启动httpd服务
[root@a7f9d0c3e3e2 /]# /usr/sbin/httpd -DFOREGROUND
```
容器服务原理:
上帝进程: 简单的说就是系统创建之初产生的第一个仅层
特点:
没有父进程,PID==1,
是所有程序的根进程
上帝进程的死亡系统实例也就关闭了
容器的上帝进程:
容器的启动进程就是上帝进程
如果容器的启动进程关等同于容器关闭
上帝进程无法在后台执行
容器的启动进程必须放在前台执行
#### 镜像编排
##### Dockerfile 详解
由于commit的局限性,Dockerfile可以设置默认的启动命令、设置环境变量、指定镜像开放某些特定的端口
| 指令 | 说明 |
| ---------- | ------------------------------------------------------ |
| FROM | 指定基础镜像(唯一) |
| RUN | 在容器内执行命令,可以写多条 |
| ADD | 把文件拷贝到容器内,如果文件是 tar.xx 格式,会自动解压 |
| COPY | 把文件拷贝到容器内,不会自动解压 |
| ENV | 设置启动容器的环境变量 |
| WORKDIR | 设置启动容器的默认工作目录(唯一) |
| CMD | 容器默认的启动参数(唯一) |
| ENTRYPOINT | 容器默认的启动命令(唯一) |
| USER | 启动容器使用的用户(唯一) |
| EXPOSE | 使用镜像创建的容器默认监听使用的端口号/协议 |
**编写 Dockerfile(案例1)**
```bash
[root@docker ~]# mkdir myimg
[root@docker ~]# vim myimg/Dockerfile
FROM mylinux:latest
CMD ["/bin/ls", "-l"]
```
**创建镜像(案例1)**
```bash
[root@docker ~]# docker build -t img1:latest myimg
......
[root@docker ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
img1 latest 9278f72f8cb1 5 seconds ago 249MB
mylinux latest e3b3d26bf0da 21 hours ago 249MB
rockylinux 8.5 210996f98b85 13 months ago 205MB
```
**创建容器(案例1)**
```bash
total 48
lrwxrwxrwx 1 root root 7 Oct 11 2021 bin -> usr/bin
drwxr-xr-x 5 root root 360 Feb 5 04:21 dev
drwxr-xr-x 1 root root 4096 Feb 5 04:21 etc
drwxr-xr-x 2 root root 4096 Oct 11 2021 home
......
```
**传递参数命令,覆盖 CMD 执行(案例1)**
```bash
[root@docker ~]# docker run -it --rm img1:latest id
uid=0(root) gid=0(root) groups=0(root)
```
----
**(方案2)ENTRYPOINT 与 CMD 执行方式为:**
**\${ENTRYPOINT} \${@-${CMD}} **
注:\$@是调用所有位置i变量 、-values是设置初始值
```bash
[root@docker ~]# vim myimg/Dockerfile
FROM mylinux:latest
ENTRYPOINT ["echo"]
CMD ["/bin/ls", "-l"]
```
**(方案2)创建镜像**
```bash
[root@docker ~]# docker build -t img2:latest myimg
......
```
**(方案2)CMD 做为参数传递,在容器内执行了 echo '/bin/ls -l'**
```bash
[root@docker ~]# docker run -it --rm img2:latest
/bin/ls -l
```
**(方案2)CMD 被替换,在容器内执行了 echo id**
```bash
[root@docker ~]# docker run -it --rm img2:latest id
id
```
**(方案3)制作测试文件**
```bash
[root@docker ~]# tar -cf myimg/myfile.tar -C /etc hosts issue
```
**(方案3)编辑Dockerfile**
```bash
[root@docker ~]# vim myimg/Dockerfile
FROM mylinux:latest
COPY myfile.tar /var/tmp/
ADD myfile.tar /tmp/
RUN id && touch /tmp/file1
USER nobody
RUN id && touch /tmp/file2
ENV mymsg="Hello World"
WORKDIR /tmp
CMD ["/bin/bash"]
```
**(方案3)创建镜像**
```bash
[root@docker ~]# docker build -t img3:latest myimg
......
```
**(方案3)运行测试**
```bash
[root@docker ~]# docker run -it --rm img3:latest
```
**(方案3)用 COPY 进来的文件还是 tar 包**
```bash
bash-4.4$ tree /var/tmp
/var/tmp
`-- myfile.tar
```
**(方案3)使用 ADD 添加的文件已经被解压了**
```bash
bash-4.4$ tree /tmp
/tmp
|-- hosts
`-- issue
```
**(方案3)USER 指令设置使用 nobody 用户运行容器**
```
bash-4.4$ id
uid=65534(nobody) gid=65534(nobody) groups=65534(nobody)
```
**(方案3)USER 指令前创建的文件是 root 权限,之后是 USER 用户权限**
```bash
bash-4.4$ ls -l /tmp/file?
-rw-r--r-- 1 root root 0 Feb 5 05:25 /tmp/file1
-rw-r--r-- 1 nobody nobody 0 Feb 5 05:25 /tmp/file2
```
**(方案3)环境变量可以直接调用**
```bash
bash-4.4$ echo ${mymsg}
Hello World
```
**(方案3)WORKDIR 把工作目录设置到 /tmp**
```bash
bash-4.4$ pwd
/tmp
```
##### Apache镜像制造
实验环境: 准备一个php页面文件
```bash
拷贝 info.php 测试文件到 /root/ 目录下
[root@ecs-proxy s4]# rsync -av public/info.php 192.168.1.32:/root/
```
**手工部署**
1. 创建容器
```bash
[root@docker ~]# docker run -it --name httpd mylinux:latest
```
2. 安装软件包
```bash
[root@975fb53cb155 /]# dnf install -y httpd php && dnf clean all
```
3. 修改配置文件
```bash
[root@975fb53cb155 /]# vim /etc/httpd/conf.modules.d/00-mpm.conf
11: LoadModule mpm_prefork_module ... ... # 去掉注释
23: # LoadModule mpm_event_module ... ... # 注释配置
[root@975fb53cb155 /]# export LANG=C
[root@975fb53cb155 /]# /usr/sbin/httpd -DFOREGROUND
# 使用快捷键 (ctrl-p, ctrl-q) 退出
```
4. 添加测试页面
```bash
[root@docker ~]# echo 'Welcome to The Apache.' >index.html
[root@docker ~]# docker cp index.html httpd:/var/www/html/
[root@docker ~]# docker cp info.php httpd:/var/www/html/
```
**制作镜像**
1. 编写 dockerfile 文件
```bash
etc/httpd/conf.modules.d/00-mpm.conf
ENV LANG=C
ADD myweb.tar.gz /var/www/html/
WORKDIR /var/www/html/
EXPOSE 80/tcp
CMD ["/usr/sbin/httpd", "-DFOREGROUND"]
[root@docker ~]# tar -czf httpd/myweb.tar.gz index.html info.php
[root@docker ~]# docker build -t httpd:latest httpd
```
2. 上转资源
```bash
[root@docker ~]# tar -czf httpd/myweb.tar.gz index.html info.php
[root@docker ~]# docker build -t httpd:latest httpd
```
**验证测试**
1. 查看镜像并创建容器
```bash
[root@docker ~]# docker images httpd:latest
REPOSITORY TAG IMAGE ID CREATED SIZE
httpd latest c1e854cde1f4 About a minute ago 299MB
[root@docker ~]# docker run -itd --name apache httpd:latest
cc2b82ad0367172c344c7207def94c4c438027c60859e94883e440b53a860a93
```
2. 查看容器地址并访问验证
```bash
[root@docker ~]# docker inspect apache |grep -i IPAddress
[root@docker ~]# curl http://172.17.0.2/info.php
Array
(
[REMOTE_ADDR] => 172.17.0.1
[REQUEST_METHOD] => GET
[HTTP_USER_AGENT] => curl/7.61.1
[REQUEST_URI] => /info.php
)
php_host: 2fbc8c132f7f
1229
[root@docker ~]# docker rm -f $(docker ps -aq)
```
##### **nginx 镜像制造**
实验准备:自行准备nginx的安装压缩包
```bash
拷贝 public/nginx-1.22.1.tar.gz 到 docker 主机
[root@ecs-proxy s4]# rsync -av public/nginx-1.22.1.tar.gz 192.168.1.32:/root/
```
**手工部署**
1. 创建容器
```bash
[root@docker ~]# docker run -itd --name web mylinux:latest
a1448547a12c15c8b1d1defa76e96f63f0f68ccb6bdeb59958ee57fc5dfac11e
```
2. 拷贝 nginx 源码包到容器内
```bash
[root@docker ~]# docker cp nginx-1.22.1.tar.gz web:/
Successfully copied 1.08MB to web:/
```
3. 进入容器配置
```bash
[root@docker ~]# docker exec -it web bash
```
4. 安装编译工具和依赖软件包
```bash
[root@a1448547a12c /]# dnf install -y openssl-devel pcre-devel gcc make
[root@a1448547a12c /]# dnf clean all
```
5. 编译安装
```bash
[root@a1448547a12c /]# tar zxf nginx-1.22.1.tar.gz
[root@a1448547a12c /]# cd nginx-1.22.1/
[root@a1448547a12c nginx-1.22.1]# ./configure --prefix=/usr/local/nginx --with-pcre --with-http_ssl_module
[root@a1448547a12c nginx-1.22.1]# make && make install
```
6. 设置默认首页
```bash
root@a1448547a12c nginx-1.22.1]# echo 'Nginx is running !' >/usr/local/nginx/html/index.html
```
7. 添加 nginx 到环境变量
```bash
root@a1448547a12c nginx-1.22.1]# echo 'Nginx is running !' >/usr/local/nginx/html/index.html
```
8. 启动服务(百度、ai)
```bash
[root@a1448547a12c nginx-1.22.1]# nginx -g "daemon off;"
```
9. 退出容器
```bash
[root@153c0df095e2 nginx-1.22.1]# exit
```
**制作镜像**
1. 将编译好的 nginx 拷贝出来(手工部署的容器)
```bash
[root@docker ~]# mkdir nginx
[root@docker ~]# docker cp web:/usr/local/nginx /root/nginx/nginx
Successfully copied 5.82MB to /root/nginx/
```
2. 编写 Dockerfile 文件
```bash
[root@docker ~]# vim nginx/Dockerfile
FROM mylinux:latest
RUN dnf install -y pcre openssl && dnf clean all
COPY nginx /usr/local/nginx
ENV PATH=${PATH}:/usr/local/nginx/sbin
WORKDIR /usr/local/nginx/html
EXPOSE 80/tcp
CMD ["nginx", "-g", "daemon off;"]
```
3. 生成镜像
```bash
[root@docker ~]# docker build -t nginx:latest nginx
......
```
**验证测试**
1. 查看镜像并创建容器
```bash
[root@docker ~]# docker images nginx:latest
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 645dd2d9a8ec 3 minutes ago 274MB
[root@docker ~]# docker run -itd --name nginx nginx:latest
e440b53a860a93cc2b82ad0367172c344c7207def94c4c438027c60859e94883
```
2. 查看容器地址并访问验证
```bash
[root@docker ~]# docker inspect nginx |grep -i IPAddress
[root@docker ~]# curl http://172.17.0.2/
Nginx is running !
[root@docker ~]# docker rm -f $(docker ps -aq)
```
**多阶段镜像(扩展)**
1. 删除之前实验解压的nginx程序,只需要用到安装压缩包
```
[root@docker ~]# rm -rf nginx/nginx
[root@docker ~]# mv /root/nginx-1.22.1.tar.gz nginx/
```
2. 编写Dockerfile
```bash
[root@docker ~]# vim nginx/Dockerfile
# 第一阶段编译程序
FROM mylinux:latest as builder
ADD nginx-1.22.1.tar.gz /
WORKDIR /nginx-1.22.1
RUN dnf install -y openssl-devel pcre-devel gcc make
RUN ./configure --prefix=/usr/local/nginx --with-pcre --with-http_ssl_module
RUN make && make install
RUN echo 'Nginx is running !' >/usr/local/nginx/html/index.html
# 第二阶段最终镜像
FROM mylinux:latest
RUN dnf install -y pcre openssl && dnf clean all
COPY --from=builder /usr/local/nginx /usr/local/nginx
ENV PATH=${PATH}:/usr/local/nginx/sbin
WORKDIR /usr/local/nginx/html
EXPOSE 80/tcp
CMD ["nginx", "-g", "daemon off;"]
[root@docker ~]# docker build -t nginx:latest nginx
......
```
##### **php-fpm 镜像制造**
**手工部署**
1. 起容器,安装软件
```bash
[root@docker ~]# docker run -it --name myphp mylinux:latest
[root@cbcf3d90c02e /]# dnf install -y php-fpm
```
2. 修改配置文件
```bash
[root@cbcf3d90c02e /]# vim /etc/php-fpm.d/www.conf
38: listen = 127.0.0.1:9000
```
3. 创建目录,并授权
```bash
[root@cbcf3d90c02e /]# mkdir /run/php-fpm
[root@cbcf3d90c02e /]# chown -R nobody.nobody /var/log/php-fpm /run/php-fpm
```
4. 使用 sudo 且换用户
```
[root@cbcf3d90c02e /]# vim /etc/php-fpm.d/www.conf
38: listen = 127.0.0.1:9000
```
5. 使用 nobody 启动服务
```bash
bash-4.4$ /usr/sbin/php-fpm --nodaemonize
[04-Sep-2023 09:58:01] NOTICE: [pool www] 'user' directive is ignored when FPM is not running as root
[04-Sep-2023 09:58:01] NOTICE: [pool www] 'group' directive is ignored when FPM is not running as root
[04-Sep-2023 09:58:01] NOTICE: fpm is running, pid 1
[04-Sep-2023 09:58:01] NOTICE: ready to handle connections
[04-Sep-2023 09:58:01] NOTICE: systemd monitor interval set to 10000ms
```
##### docker 私有仓库
**主机清单:**
| 主机名 | ip地址 | 最低配置 |
| -------- | ------------ | ----------- |
| registry | 192.168.1.35 | 2CPU,4G内存 |
**registry 安装**
```bash
# 在 registry 上安装私有仓库
[root@registry ~]# dnf install -y docker-distribution
# 启动私有仓库,并设置开机自启动
[root@registry ~]# systemctl enable --now docker-distribution
```
**客户端配置**
- **所有 node 节点都需要配置**
```bash
[root@docker ~]# vim /etc/hosts
192.168.1.35 registry
# 修改配置文件
[root@docker ~]# vim /etc/docker/daemon.json
{
"registry-mirrors": ["http://registry:5000"],
"insecure-registries":["registry:5000"]
}
# 重启服务生效
[root@docker ~]# systemctl restart docker
[root@docker ~]# docker info
```
**上传镜像**
1. 给 nginx 镜像设置标签
2. 上传 nginx 镜像
3. 上传 php-fpm 镜像
4. 上传 httpd 镜像
**验证测试**
```bash
查看镜像名称: curl http://仓库IP:5000/v2/_catalog
查看镜像标签: curl http://仓库IP:5000/v2/镜像路径/tags/list
使用易读格式: python3 -m json.tool
```
1. 查看仓库中所有镜像的名称
```bash
[root@docker ~]# curl http://registry:5000/v2/_catalog
{"repositories":["img/myimg", "library/httpd"]}
```
2. 查看某一镜像的所有标签
```bash
[root@docker ~]# curl http://registry:5000/v2/img/myimg/tags/list
{"name":"img/myimg","tags":["nginx", "php-fpm"]}
```
3. 易读格式查看镜像名称
```bash
[root@docker ~]# curl http://registry:5000/v2/img/myimg/tags/list
{"name":"img/myimg",
"tags":["nginx", "php-fpm"]
}
```
4. 易读格式查看镜像标签
```bash
[root@docker ~]# curl -s http://registry:5000/v2/img/myimg/tags/list |python3 -m json.tool
{
"name": "img/myimg",
"tags": [
"nginx",
"php-fpm"
]
}
```
**创建容器**
1.  删除所有容器
```bash
[root@docker ~]# docker rm -f $(docker ps -aq)
......
```
2. 删除所有镜像
```bash
[root@docker ~]# docker rmi -f $(docker images -q)
......
```
3. 使用仓库中的镜像运行容器
```bash
[root@docker ~]# docker run -itd --rm registry:5000/img/myimg:nginx
2b7cd6d88a7665dbea0a4b3d99478e9f302c0a5661d7676d6d3bd3cb6d181
```
4. library 是默认路径,可以省略路径地址
```bash
[root@docker ~]# docker run -itd --rm httpd:latest
634766f788d665dbea0a4b39709e0a2cc8624fd99478e9f302c0a5661d767
```
#### 对外发布服务
##### 端口绑定
- docker run -itd -p 宿主机端口:容器端口 镜像:标签
1. 端口绑定
```bash
[root@docker ~]# docker run -itd --rm --name web -p 80:80 myos:nginx
```
2. 绑定后,直接访问宿主机的 IP 地址即可
```bash
[root@docker ~]# curl http://192.168.1.31
Nginx is running !
```
3. 一个端口只能绑定唯一容器
```bash
[root@docker ~]# docker run -itd --rm -p 80:80 myos:httpd
......
Bind for 0.0.0.0:80 failed: port is already allocated.
```
4. 使用不同端口绑定
```bash
[root@docker ~]# docker run -itd --rm -p 8080:80 myos:httpd
3c22b1d9c7484c03648d9c64fe073953fb9460015b6f2a
```
5. 绑定后,访问验证
```bash
[root@docker ~]# curl http://192.168.1.31:8080
Welcome to The Apache.
```
##### 容器存储卷
- docker run -itd -v 宿主机对象:容器内对象 镜像:标签
**数据卷目录**
1. 创建卷目录,并添加测试页面
```bash
[root@docker ~]# mkdir /var/webroot
[root@docker ~]# echo "hello world" >/var/webroot/index.html
```
2. 使用卷映射数据目录
```bash
[root@docker ~]# docker rm -f web
[root@docker ~]# docker run -itd --rm --name web -p 80:80 \
-v /var/webroot:/usr/local/nginx/html myos:nginx
[root@docker ~]# curl http://192.168.1.31/
hello worl
```
3. 修改数据卷内容可以直接在容器内体现
```bash
[root@ecs-proxy s4]# rsync -av public/info.php 192.168.1.31:/var/webroot/
[root@ecs-proxy s4]# curl http://192.168.1.31/info.php
404 Not Found
404 Not Found
nginx/1.22.1