【运维知识大神篇】运维人必学的Docker教程3(自定义网络+部署服务实战+容器重启策略+自动构建镜像技术Dockerfile详解+使用Docker一键部署wordpress的两种解法)

本篇文章继续给大家介绍docker的内容,包括自定义网络,容器重启策略,自动构建镜像技术Dockerfile,使用Dockerfile制作游戏镜像,使用Dockerfile一键部署wordpress的实战(一个镜像和四个镜像两种方案)。

目录

自定义网络

一、网络类型

二、网络操作基础命令

1、查看网络信息

2、创建网络

3、网络分配

4、移除网络

5、删除网络

6、自定义网络实现容器互通

三、自定义网络部署实战:部署Zabbix5.4

容器的重启策略

一、重启策略种类

二、参考案例

自动构建镜像技术Dockerfile

一、相较手动构建的优缺点

二、常用的Dockerfile指令

1、常用指令详解之FROM、MAINTAINER、LABEL、RUN、CMD、ENV、CMD

2、用dockerfile基于centos构建nginx镜像,要求越小越好 

3、基于CentOS制作游戏镜像(新增指令:WORKDIR、COPY、ADD、EXPOSE、VOLUME)

4、缓存问题

5、基于Ubuntu:20.04制作游戏镜像

实战:使用Dockerfile一键构建WordPress

解法1:一个镜像

解法2:多个镜像

1、mysql部分处理

2、php部分处理

3、nginx部分处理

4、准备代码文件并部署

5、用户统一问题


自定义网络

一、网络类型

docker的网络类型有几种,有说3种,有说4种,有说5种的,我下面列了4种,5种是多了user-defined,3种是少了container。

none           没有网卡,只有一个本地回环网卡lo。

host            不会产生新的网络名称空间,直接使用宿主机的网络名称空间,效率极高,缺陷就是宿主机和监听端口和容器可能会存在冲突的风险。

bridge         桥接网卡,相当于VM的NAT网络,会产生一块新的网卡,会生成一对设备对,一端在容器里,另一端在宿主机上。

container    不会创建新的网卡,和指定的容器共享网络名称空间。

二、网络操作基础命令

1、查看网络信息

列出已有的网络

[root@Docker01 ~]# docker network ls    #有三个无法被删除的默认的网络
NETWORK ID     NAME      DRIVER    SCOPE
4f03c7e747a0   bridge    bridge    local
13bfd5425452   host      host      local
3d470b5c703b   none      null      local

查看网络的详细信息

[root@Docker01 ~]# docker network inspect bridge
[
    {
        "Name": "bridge",
        "Id": "4f03c7e747a040ddba8d61dfe2f7c25ee2af956d6e95ae2cc8788eda5a540df4",
        "Created": "2023-06-07T22:33:26.04028532+08:00",
        "Scope": "local",
        "Driver": "bridge",
        "EnableIPv6": false,
        "IPAM": {
            "Driver": "default",
            "Options": null,
            "Config": [
                {
                    "Subnet": "172.17.0.0/16",    #子网
                    "Gateway": "172.17.0.1"       #网关
                }
            ]
        },
        "Internal": false,
        "Attachable": false,
        "Ingress": false,
        "ConfigFrom": {
            "Network": ""
        },
        "ConfigOnly": false,
        "Containers": {
            "6df7b592ce07bedf0090a19255483e300700a29c9ddb1b6e24e22a05651f721c": {
                "Name": "quizzical_chebyshev",
                "EndpointID": "68f5b4cbe08dd72e16dddc967ee989737afb1ea9239e2d37aacce28aab6ba459",
                "MacAddress": "02:42:ac:11:00:02",
                "IPv4Address": "172.17.0.2/16",
                "IPv6Address": ""
            },
            "c159b1f9d2cd187dcae9716eb7c47d5a2262a95a145163dce7c4f64e87c8197f": {
                "Name": "c3-bridge",
                "EndpointID": "0bd1a3a6737f4a2df70d689315dfaeb16c3e1b66e09844156474dacd06e476bd",
                "MacAddress": "02:42:ac:11:00:03",
                "IPv4Address": "172.17.0.3/16",
                "IPv6Address": ""
            }
        },
        "Options": {
            "com.docker.network.bridge.default_bridge": "true",
            "com.docker.network.bridge.enable_icc": "true",
            "com.docker.network.bridge.enable_ip_masquerade": "true",
            "com.docker.network.bridge.host_binding_ipv4": "0.0.0.0",
            "com.docker.network.bridge.name": "docker0",
            "com.docker.network.driver.mtu": "1500"
        },
        "Labels": {}
    }
]

2、创建网络

创建网络,--subnet指定子网,--ip-range指定IP网段,--gateway指定网管地址

[root@Docker01 ~]# docker network create --subnet 172..20.0.0/16 --ip-range 172.20.100.0/24 --gateway 172.20.0.254 koten-ip
525a45594929dce9e97a4233d98e49315b410fa60961d2e0d5a9643c2e6325d6
[root@Docker01 ~]# docker network ls
NETWORK ID     NAME       DRIVER    SCOPE
4f03c7e747a0   bridge     bridge    local
13bfd5425452   host       host      local
525a45594929   koten-ip   bridge    local
3d470b5c703b   none       null      local

3、网络分配

可以在容器启动的时候自定义网络,使用alpine轻量级Linux镜像,这个镜像想进入不能bash,只能sh

[root@Docker01 ~]# docker run -id --name c1-none --network none alpine
393a5bc81fdeaf48441570d80beb684c2193ab11bf70ff26d3c55c6ec1b759d6
[root@Docker01 ~]# docker run -id --name c2-host --network host alpine
d1b1dc6134514a0fcd51208956912693e9c2c955185bec39553e9b7807eea62e
[root@Docker01 ~]# docker run -id --name c3-bridge --network bridge alpine
c159b1f9d2cd187dcae9716eb7c47d5a2262a95a145163dce7c4f64e87c8197f
[root@Docker01 ~]# docker run -id --name c4-container --network container:c3-bridge alpine
724ac6a0e42c693c1299df708c79440243e00ad4b07ced993040d26c107f0fa8
[root@Docker01 ~]# docker ps
CONTAINER ID   IMAGE                   COMMAND                  CREATED          STATUS          PORTS                                                                          NAMES
724ac6a0e42c   alpine                  "/bin/sh"                13 minutes ago   Up 13 minutes                                                                                  c4-container
c159b1f9d2cd   alpine                  "/bin/sh"                14 minutes ago   Up 14 minutes                                                                                  c3-bridge
d1b1dc613451   alpine                  "/bin/sh"                14 minutes ago   Up 14 minutes                                                                                  c2-host
393a5bc81fde   alpine                  "/bin/sh"                15 minutes ago   Up 15 minutes                                                                                  c1-none

也可以将一个网络分配给一个正在运行的容器

[root@Docker01 ~]# docker network connect koten-ip quizzical_chebyshev

4、移除网络

将正在运行的容器的网络移除

[root@Docker01 ~]# docker network disconnect koten-ip quizzical_chebyshev

5、删除网络

移除所有未被使用的网络,注意默认网络无法被移除

[root@Docker01 ~]# docker network prune -f
Deleted Networks:
koten-ip

移除一个或多个网络

[root@Docker01 ~]# docker network create net1 
00bc0123b593d614493dcbdfae203e674a8a499e746c452593bacdf0f8b07e2c
[root@Docker01 ~]# docker network create net2
2929ecbdc0b75e7fc98dd33053026a90c3ecb9bacd014bc6d2cc3a22c5450694
[root@Docker01 ~]# docker network rm net1 net2
net1
net2
[root@Docker01 ~]# docker network ls
NETWORK ID     NAME      DRIVER    SCOPE
4f03c7e747a0   bridge    bridge    local
13bfd5425452   host      host      local
3d470b5c703b   none      null      local

6、自定义网络实现容器互通

使用--link,此时c2可以连通c1,c1不能连通c2

[root@Docker01 ~]# docker run  --name c1 -id alpine
51e40d500de437beb6a23fe0d706b5908f62ca4ad8dcf05e85832148fda1f1d1
[root@Docker01 ~]# docker run  --name c2 -id --link c1 alpine
cc5897fdc9d493f09389a9e90939162d8207907e5542a5c00058c0cad4d007ce
[root@Docker01 ~]# docker exec c2 ping c1
PING c1 (172.17.0.4): 56 data bytes
64 bytes from 172.17.0.4: seq=0 ttl=64 time=0.650 ms
^C
[root@Docker01 ~]# docker exec c1 ping c2
ping: bad address 'c2'

因为--link底层原理是被关联的容器的主机名会被写入关联容器的/etc/hosts文件中

[root@Docker01 ~]# docker exec -it c1 sh
/ # cat /etc/hosts 
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.4	51e40d500de4
/ # exit
[root@Docker01 ~]# docker exec -it c2 sh
/ # cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::0	ip6-localnet
ff00::0	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.17.0.4	c1 51e40d500de4
172.17.0.5	cc5897fdc9d4

三、自定义网络部署实战:部署Zabbix5.4

1、创建自定义网络

[root@Docker01 ~]# docker network create --subnet 172.20.0.0/16 --ip-range 172.20.240.0/20 zabbix-net
9aa57c55ae328b4e8bc60900ff5ee3e07f4d0c22f58e9e6191276e6748521eea

2、运行MySQL服务

docker run --name mysql-server -t \
           -e MYSQL_DATABASE="zabbix" \
           -e MYSQL_USER="zabbix" \
           -e MYSQL_PASSWORD="zabbix_pwd" \
           -e MYSQL_ROOT_PASSWORD="root_pwd" \
           --network=zabbix-net \
           --restart unless-stopped \
           -d mysql:8.0 \
           --character-set-server=utf8 --collation-server=utf8_bin \
           --default-authentication-plugin=mysql_native_password

3、启动Zabbix Java网关实例,方便监控Java软件

docker run --name zabbix-java-gateway -t \
             --network=zabbix-net \
             --restart unless-stopped \
             -d zabbix/zabbix-java-gateway:alpine-5.4-latest

4、启动Zabbix server实例,并将其关联到已创建的MySQL server实例

docker run --name zabbix-server-mysql -t \
             -e DB_SERVER_HOST="mysql-server" \
             -e MYSQL_DATABASE="zabbix" \
             -e MYSQL_USER="zabbix" \
             -e MYSQL_PASSWORD="zabbix_pwd" \
             -e MYSQL_ROOT_PASSWORD="root_pwd" \
             -e ZBX_JAVAGATEWAY="zabbix-java-gateway" \
             --network=zabbix-net \
             -p 10051:10051 \
             --restart unless-stopped \
             -d zabbix/zabbix-server-mysql:alpine-5.4-latest

5、启动Zabbix Web界面,并将其关联到已经创建的MySQL server和Zabbix server实例

docker run --name zabbix-web-nginx-mysql -t \
             -e ZBX_SERVER_HOST="zabbix-server-mysql" \
             -e DB_SERVER_HOST="mysql-server" \
             -e MYSQL_DATABASE="zabbix" \
             -e MYSQL_USER="zabbix" \
             -e MYSQL_PASSWORD="zabbix_pwd" \
             -e MYSQL_ROOT_PASSWORD="root_pwd" \
             --network=zabbix-net \
             -p 80:8080 \
             --restart unless-stopped \
             -d zabbix/zabbix-web-nginx-mysql:alpine-5.4-latest

 

容器的重启策略

一、重启策略种类

1、always                 只要容器退出(异常退出+重启docker服务),就会重启容器

2、no                        只要容器退出(异常退出+重启docker服务),都不会重启

3、on-failure             等效于always

4、on-failure:max      当异常退出时达到max次数时,就不会重启了,当容器被手动重启时,之前失败的次数会被清零

5、unless-stopped     当重启docker服务时,若容器处于运行状态,才会重启

二、参考案例

1、启动五种重启策略的容器

[root@Docker01 ~]# docker run --name c1-always --restart always -id alpine
561f48b35f250a8916a23f6972df1ba7bf075398fb93f7f34bc7b0e27c4a70fb
[root@Docker01 ~]# docker run --name c2-no --restart no -id alpine
739e6cfd9eac11ec9fc619457e227157c92a8c752ac6e462a1707f76e3a40c98
[root@Docker01 ~]# docker run --name c3-on-failure --restart on-failure -id alpine
1835e29b1fbee208db8f59ce0996b3f87aea4c2166c9ba85e8151a8031f31264
[root@Docker01 ~]# docker run --name c4-on-failure-max --restart on-failure:3 -id alpine
649241c38969ffc4385206aaec7395dfdafcfd2aa23b5d7c4cf7cde9edca7f44
[root@Docker01 ~]# docker run --name c5-unless-stopped --restart unless-stopped -id alpine
a56e9e5ef48a76fd20f95769d3dab65251bde4c509ce698ae57bcb7808fd5cca

 2、启动后,所有容器均为up状态

[root@Docker01 ~]# docker ps
CONTAINER ID   IMAGE     COMMAND     CREATED              STATUS              PORTS     NAMES
a56e9e5ef48a   alpine    "/bin/sh"   22 seconds ago       Up 20 seconds                 c5-unless-stopped
649241c38969   alpine    "/bin/sh"   27 seconds ago       Up 26 seconds                 c4-on-failure-max
1835e29b1fbe   alpine    "/bin/sh"   About a minute ago   Up About a minute             c3-on-failure
739e6cfd9eac   alpine    "/bin/sh"   About a minute ago   Up About a minute             c2-no
561f48b35f25   alpine    "/bin/sh"   About a minute ago   Up About a minute             c1-always

3、正常重启服务发现除了no策略的容器其他都可以启动

[root@Docker01 ~]# systemctl restart docker
[root@Docker01 ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND     CREATED          STATUS                       PORTS     NAMES
a56e9e5ef48a   alpine    "/bin/sh"   10 minutes ago   Up 2 minutes                           c5-unless-stopped
649241c38969   alpine    "/bin/sh"   10 minutes ago   Up 2 minutes                           c4-on-failure-max
1835e29b1fbe   alpine    "/bin/sh"   11 minutes ago   Up 2 minutes                           c3-on-failure
739e6cfd9eac   alpine    "/bin/sh"   11 minutes ago   Exited (137) 2 minutes ago             c2-no
561f48b35f25   alpine    "/bin/sh"   11 minutes ago   Up 2 minutes                           c1-always

4、尝试kill -9一次,模拟异常退出,unless-stopped策略的容器没有启动,此时查看on-failure-max的容器,发现重启次数为1,最大重启次数为3

#kill掉启用的容器
[root@Docker01 ~]# kill -9 `ps -ef | grep "/bin/sh" | grep -v grep | awk '{print $2}'`
[root@Docker01 ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND     CREATED          STATUS                            PORTS     NAMES
a56e9e5ef48a   alpine    "/bin/sh"   13 minutes ago   Exited (137) About a minute ago             c5-unless-stopped
649241c38969   alpine    "/bin/sh"   13 minutes ago   Up 52 seconds                               c4-on-failure-max
1835e29b1fbe   alpine    "/bin/sh"   14 minutes ago   Up 52 seconds                               c3-on-failure
739e6cfd9eac   alpine    "/bin/sh"   14 minutes ago   Exited (137) 5 minutes ago                  c2-no
561f48b35f25   alpine    "/bin/sh"   14 minutes ago   Up 53 seconds                               c1-always
[root@Docker01 ~]# docker inspect c4-on-failure-max 
......
        "RestartCount": 1,
......
            "RestartPolicy": {
                "Name": "on-failure",
                "MaximumRetryCount": 3
            },
......

5、再尝试kill -9两次,模拟异常退出,发现on-failure:max的容器也停止了,此时重启策略已经达到最大值3

[root@Docker01 ~]# docker ps -a
CONTAINER ID   IMAGE     COMMAND     CREATED          STATUS                        PORTS     NAMES
a56e9e5ef48a   alpine    "/bin/sh"   27 minutes ago   Exited (137) 14 minutes ago             c5-unless-stopped
649241c38969   alpine    "/bin/sh"   27 minutes ago   Exited (137) 3 seconds ago              c4-on-failure-max
1835e29b1fbe   alpine    "/bin/sh"   27 minutes ago   Up 2 seconds                            c3-on-failure
739e6cfd9eac   alpine    "/bin/sh"   27 minutes ago   Exited (137) 18 minutes ago             c2-no
561f48b35f25   alpine    "/bin/sh"   28 minutes ago   Up 2 seconds                            c1-always
[root@Docker01 ~]# docker inspect c4-on-failure-max 
......
        "RestartCount": 3,
......

自动构建镜像技术Dockerfile

Dockerfile,是构建镜像的一种自动化的流程,类似于ansible的剧本,也是把想执行的流程通过一定的指令和格式写出来,然后按顺序执行,也类似与shell脚本,elk配置文件,我感觉Linux的技术都是互通的,万变不离其宗。

一、相较手动构建的优缺点

1、手动构建镜像

优点是简单,不用学习新的东西,在虚拟机中如何操作,在容器中就如何操作

缺点是不易于扩展,修改比较麻烦,比如COMMAND指令,每次修改都需要重新运行一个新的容器并提交为一个新的镜像

2、自动构建镜像

优点是扩展性强,修改起来比较方便,缺点是体积小,只要按照步骤做就能得出结果。

缺点是,前期需要学习新的技术点。

二、常用的Dockerfile指令

常用的Dockergfile指令也就十几条,其他的遇到了看帮助就行,现学现用,常见的有FORM、RUN、CMD、ENTRYPOINT、EXPOSE、VOLUME、ADD、COPY、ONBUILD、HEALTHCHECK、ARG、ENV、LABEL、MAINTAINER

1、常用指令详解之FROM、MAINTAINER、LABEL、RUN、CMD、ENV、CMD

编写dockerfile

[root@Docker01 ~]# cat dockerfile
# 指定基础镜像
FROM centos:7

# 生声明作者信息,官方已经弃用,只能声明一行,建议使用LABEL
MAINTAINER koten

# LABEL可以基于key=value方式指定信息
LABEL author=koten \
      subject=linux \
      hobby=docker

# 在容器中运行命令
RUN mkdir /koten

# 向容器传递环境变量,基于key=value的语法格式
ENV author=koten \
    version=1.0

# 容器启动时的命令
CMD ["tail","-f","/etc/hosts"]

根据dockerfile编译成镜像,可以指定,也可以用.表示当前,让它自己去找名为dockerfile/Dockerfile的文件

[root@Docker01 ~]# docker image build -t test:v0.1 .
[+] Building 0.5s (6/6) FINISHED                    
 => [internal] load build definition from doc  0.0s
 => => transferring dockerfile: 392B           0.0s
 => [internal] load .dockerignore              0.0s
 => => transferring context: 2B                0.0s
 => [internal] load metadata for docker.io/li  0.0s
 => CACHED [1/2] FROM docker.io/library/cento  0.0s
 => [2/2] RUN mkdir /koten                     0.4s
 => exporting to image                         0.0s
 => => exporting layers                        0.0s
 => => writing image sha256:c3f193dae16f6c5a0  0.0s
 => => naming to docker.io/library/test:v0.1   0.0s

指定路径和dockerfile名称,若dockerfile名称为1.df,在/koten目录下

[root@Docker01 ~]# docker image build -t test:v0.1 1.df /koten

2、用dockerfile基于centos构建nginx镜像,要求越小越好 

编写dockerfile,用多条run指令发现无法删除缓存,因为涉及联合文件系统,后面那层删了缓存,但是上层数据还在,所以合并后还是体积大

[root@Docker01 ~]# cat dockerfile 
# 指定基础镜像
FROM centos:7

# 在容器中运行命令
RUN curl -s -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
RUN curl -s -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo
RUN yum -y install nginx
RUN rm -rf /var/cache/yum/

# 容器启动时的命令
CMD ["nginx","-g","daemon off"]
[root@Docker01 ~]# docker build -t koten-nginx:v1.0 .
[root@Docker01 ~]# docker images
REPOSITORY           TAG       IMAGE ID       CREATED          SIZE
koten-nginx          v1.0      8aec38ab7701   30 minutes ago   486MB

 将多条run指令合成一条,发现镜像变小了

[root@Docker01 ~]# cat dockerfile
# 指定基础镜像
FROM centos:7

# 在容器中运行命令
RUN curl -s -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
    curl -s -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo && \
    yum -y install nginx && \
    rm -rf /var/cache/yum/

# 容器启动时的命令
CMD ["nginx","-g","daemon off"]
[root@Docker01 ~]# docker build -t koten-nginx:v2.0 .
[root@Docker01 ~]# docker images
REPOSITORY           TAG       IMAGE ID       CREATED          SIZE
koten-nginx          v2.0      5ffea6117d49   6 minutes ago    262MB
koten-nginx          v1.0      8aec38ab7701   30 minutes ago   486MB

3、基于CentOS制作游戏镜像(新增指令:WORKDIR、COPY、ADD、EXPOSE、VOLUME)

在网上找到个里面有小游戏的镜像,我们pull到自己的主机,再run启动,exec进去,将游戏文件拷贝出来,获得游戏文件和nginx配置文件(下载链接在文末),此时我们稍作修改,制作成自己的镜像

准备需要的文件

[root@Docker01 ~]# mkdir game-dockerfile
[root@Docker01 ~]# cd game-dockerfile
[root@Docker01 game-dockerfile]# ls
games.conf  koten-games.tar.gz

编写dockerfile

[root@Docker01 game-dockerfile]# cat dockerfile
# 指定基础镜像
FROM centos:7

# 声明作者信息,官方已弃用,建议使用LABEL
MAINTAINER koten

# LABEL可以基于key=value方式指定信息
LABEL author=koten \
      CSDN=我是koten \
      hobby=docker

# 修改centos镜像的yum源为国内地址,并安装nginx,sshd服务(运行时,不能阻塞RUN指令,否则终止编译)
RUN sed -e 's|^mirrorlist=|#mirrorlist=|g' \
        -e 's|^#baseurl=http://mirror.centos.org/centos|baseurl=https://mirrors.tuna.tsinghua.edu.cn/centos|g' \
        -i.bak \
        /etc/yum.repos.d/CentOS-*.repo && \
    yum -y install epel-release && \
    sed -e 's!^metalink=!#metalink=!g' \
        -e 's!^#baseurl=!baseurl=!g' \
        -e 's!https\?://download\.fedoraproject\.org/pub/epel!https://mirrors.tuna.tsinghua.edu.cn/epel!g' \
        -e 's!https\?://download\.example/pub/epel!https://mirrors.tuna.tsinghua.edu.cn/epel!g' \
        -i /etc/yum.repos.d/epel*.repo && \
    yum -y install nginx openssh-server initscripts && \
    rm -rf /var/cache/yum


# 指定工作目录,若不指定则默认路径为"/"
WORKDIR /usr/local/nginx/html 

# 将宿主机的文件拷贝到容器的指定路径
COPY config/games.conf  /etc/nginx/conf.d/
COPY scripts/start.sh /

# 如果文件为tar包,会自动解压并删除源文件。
ADD softwares/koten-games.tar.gz /usr/local/nginx/html/

# 暴露容器的80端口
EXPOSE 80 22 

# 将容器的指定路径进行持久化,会产生随机(匿名)存储卷
VOLUME /usr/local/nginx/html/

# 容器启动时的命令
CMD ["bash","-x","/start.sh"]

编写运行dockfile的脚本,实现执行dockerfile,打包出镜像,基于镜像启动容器,查看容器信息的效果

[root@Docker01 game-dockerfile]# cat build.sh
#!/bin/bash

docker build -t koten-games:v0.$1 -f Dockerfile .

docker container run -d -p 80:80 koten-games:v0.$1

docker ps -l

编写容器启动的命令脚本

[root@Docker01 scripts]# cat start.sh
#!/bin/sh

nginx

if [ -n "$1" ];then
   echo root:$1 | chpasswd
elif [ -n "$KOTEN_ADMIN" ]; then
   echo root:$KOTEN_ADMIN | chpasswd
else 
   echo root:"123" | chpasswd
fi

ssh-keygen -A

/usr/sbin/sshd -D

将文件调整至最终的目录结构

[root@Docker01 game-dockerfile]# tree
.
├── build.sh
├── config
│   └── games.conf
├── dockerfile
├── scripts
│   └── start.sh
└── softwares
    └── koten-games.tar.gz

3 directories, 5 files

执行build脚本

[root@Docker01 game-dockerfile]# sh build.sh 1
[+] Building 0.1s (11/11) FINISHED                                                                      
 => [internal] load build definition from dockerfile                                               0.0s
 => => transferring dockerfile: 1.70kB                                                             0.0s
 => [internal] load .dockerignore                                                                  0.0s
 => => transferring context: 2B                                                                    0.0s
 => [internal] load metadata for docker.io/library/centos:7                                        0.0s
 => [1/6] FROM docker.io/library/centos:7                                                          0.0s
 => [internal] load build context                                                                  0.0s
 => => transferring context: 207B                                                                  0.0s
 => CACHED [2/6] RUN sed -e 's|^mirrorlist=|#mirrorlist=|g'         -e 's|^#baseurl=http://mirror  0.0s
 => CACHED [3/6] WORKDIR /usr/local/nginx/html                                                     0.0s
 => CACHED [4/6] COPY config/games.conf  /etc/nginx/conf.d/                                        0.0s
 => CACHED [5/6] COPY scripts/start.sh /                                                           0.0s
 => CACHED [6/6] ADD softwares/koten-games.tar.gz /usr/local/nginx/html/                           0.0s
 => exporting to image                                                                             0.0s
 => => exporting layers                                                                            0.0s
 => => writing image sha256:9a3aec1843ee9eec19f55a1e875c7cad7336ad1178a54ad5b3c559ff896ce5b4       0.0s
 => => naming to docker.io/library/koten-games:v0.1                                                0.0s
581fd7b99bdbb7b48377ea64531ae28adfdd3fcad2c27d695400d674cf0ca2c5
CONTAINER ID   IMAGE              COMMAND               CREATED         STATUS                  PORTS                                       NAMES
581fd7b99bdb   koten-games:v0.1   "bash -x /start.sh"   6 seconds ago   Up Less than a second   22/tcp, 0.0.0.0:80->80/tcp, :::80->80/tcp   busy_noether

windows进行hosts解析,浏览器访问查看效果

10.0.0.201 game01.koten.com
10.0.0.201 game02.koten.com
10.0.0.201 game03.koten.com
10.0.0.201 game04.koten.com
10.0.0.201 game05.koten.com
10.0.0.201 game06.koten.com
10.0.0.201 game07.koten.com
10.0.0.201 game08.koten.com
10.0.0.201 game09.koten.com
10.0.0.201 game10.koten.com
10.0.0.201 game11.koten.com
10.0.0.201 game12.koten.com
10.0.0.201 game13.koten.com
10.0.0.201 game14.koten.com
10.0.0.201 game15.koten.com
10.0.0.201 game16.koten.com
10.0.0.201 game17.koten.com

game01.koten.com一直到game17.koten.com,都部署完毕 

 

4、缓存问题

执行dockerfile后会在本机产生缓存,好处是以后执行可以调用缓存,速度就快了,但是注意不能调换里面指令的顺序,调换就无法使用缓存了

构建镜像时不使用缓存

docker build --no-cache -t my-image .

还可以一键清除缓存

docker builder prune

保留最近一定时间的缓存,删除之前的缓存,可以通过--filter实现,例如保留最近1天的缓存

docker builder prune --filter 'until=24h'

5、基于Ubuntu:20.04制作游戏镜像

我们将上面目录拷贝一份,CentOS和Ubuntu命令有一定的差异,我们修改下配置文件即可。

[root@Docker01 ~]# cp -r game-dockerfile/ game-dockerfile-ubuntu/

执行部署脚本

[root@Docker01 game-dockerfile-ubuntu]# sh build.sh 2

实战:使用Dockerfile一键构建WordPress

有两种解法,一是把鸡蛋放在同一个篮子nginx,php,wordpress,mysql,此时一个网络就可以,二是拆分成4个镜像,需要自定义网络,我们这边可以都尝试下。

解法1:一个镜像

我们拷贝上面的dockerfile目录,准备代码文件及nginx配置文件,编写dockerfile

[root@Docker01 ~]# cp game-dockerfile wordpress-dockerfile
[root@Docker01 ~]# cd wordpress-dockerfile/

编写dockerfile

[root@Docker01 wordpress-dockerfile]# cat dockerfile
FROM centos:7

# 配置国内软件源
RUN curl -s -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
    sed -i -e '/mirrors.cloud.aliyuncs.com/d' \ 
           -e '/mirrors.aliyuncs.com/d' /etc/yum.repos.d/CentOS-Base.repo && \
    curl  -s -o /etc/yum.repos.d/epel.repo http://mirrors.aliyun.com/repo/epel-7.repo

# 安装php,nginx,sshd,mysql-mariadb
RUN yum -y install http://rpms.remirepo.net/enterprise/remi-release-7.rpm && \
    yum -y install php74-php-cli php74-php-common php74-php-devel php74-php-embedded php74-php-fpm php74-php-gd php74-php-mbstring php74-php-mysqlnd php74-php-pdo php74-php-opcache php74-php-xml php74-php-soap nginx mariadb-server && \
    ln -s /opt/remi/php74/root/usr/bin/php /usr/local/bin/php && \
    rm -rf /var/cache/yum


# 修改PHP的运行用户和nginx是相同的用户,否则服务器报错500
RUN sed -ri '/^group/s/(group = )apache/\1nginx/' /etc/opt/remi/php74/php-fpm.d/www.conf && \
    sed -ri '/^user/s/(user = )apache/\1nginx/' /etc/opt/remi/php74/php-fpm.d/www.conf && \
    install -d /koten/wp -o nginx -g nginx


# 拷贝配置文件
COPY config/wp.conf /etc/nginx/conf.d/wp.conf

# 拷贝测试PHP环境
#COPY softwares/phpinfo.php /koten/wp
#COPY softwares/mysql.php  /koten/wp/

# 拷贝启动脚本
COPY scripts/start.sh /

# 将WordPress软件包拷贝到nginx的站点目录
ADD softwares/wordpress-6.2.2.tar.gz /koten/wp

# 给nginx用户授权WordPress站点目录的访问权限
RUN chown nginx:nginx -R /koten/wp/wordpress

EXPOSE 80 

# CMD ["tail","-f","/etc/hosts"]
CMD ["bash","-x","/start.sh"]

修改容器启动脚本

[root@Docker01 wordpress-dockerfile]# cat build.sh
#!/bin/bash

docker container rm -f `docker container ps -qa`
docker build -t wp:v0.$1 .
docker run -dp 80:80 wp:v0.$1
docker ps -l

修改容器启动时运行的命令脚本

[root@Docker01 wordpress-dockerfile]# cat scripts/start.sh
#!/bin/bash

# 启动php
/opt/remi/php74/root/usr/sbin/php-fpm

# 启动nginx
# nginx -g "daemon off;"
nginx

# 初始化并启动mariadb,需要一定的时间
/usr/libexec/mariadb-prepare-db-dir
/usr/bin/mysqld_safe --basedir=/usr &

# 初始化MySQL的密码
sleep 3
/usr/bin/mysqladmin -u root password '123'

# 创建数据库
mysql -p123 -e "CREATE DATABASE wordpress;"

# 阻塞容器,防止容器退出
tail -f /etc/hosts

修改nginx配置文件

[root@Docker01 wordpress-dockerfile]# cat config/wp.conf
server {
   listen 80;
   server_name wp.koten.com;
   # root /koten/wp;
   root /koten/wp/wordpress;
   index index.html index.php;
 
  location ~ \.php$ {
     fastcgi_pass 127.0.0.1:9000;
     fastcgi_index index.php;
     fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
     include fastcgi_params;
  }
}

准备代码文件,最终数据目录如下所示

[root@Docker01 wordpress-dockerfile]# tree
.
├── build.sh
├── config
│   └── wp.conf
├── dockerfile
├── scripts
│   └── start.sh
└── softwares
    └── wordpress-6.2.2.tar.gz

3 directories, 5 files

执行build脚本,构建镜像并运行

[root@Docker01 wordpress-dockerfile]# sh build.sh 1
......
CONTAINER ID   IMAGE     COMMAND               CREATED        STATUS                  PORTS                               NAMES
73d3da5d6f78   wp:v0.1   "bash -x /start.sh"   1 second ago   Up Less than a second   0.0.0.0:80->80/tcp, :::80->80/tcp   blissful_hofstadter

windows进行hosts解析,浏览器访问部署wordpress

 

解法2:多个镜像

拆分多个镜像的好处有很多,可以有更好的伸缩性,例如某个服务需要更多的数据库资源,只需要增加数据库镜像实例,不必同时增加其他镜像的实例;当有的镜像报错时,也不会影响其他镜像的运行;更容器去部署维护,也更具有安全性。

最好是按照wordpress的要求去选择服务版本的指定镜像,企业里也是根据业务要求,跟开发沟通去选择指定服务版本的镜像。

拆分镜像用多个dockerfile太复杂了,我这边直接用命令行了,因为我拆的比较彻底,拆成nginx、php、mysql三个部分

1、mysql部分处理

运行镜像并挂载相关文件

docker run -d -p 3306:3306 --name mysql -v /wordpress/mysql/conf:/etc/mysql/conf.d -v /wordpress/mysql/data:/var/lib/mysql -e MYSQL_ROOT_PASSWORD=123456 mysql:5.7

进入容器创建wordpress数据库

[root@Docker01 ~]# docker exec -it mysql bash
root@1a30f24af976:/# mysql -p123456
...
mysql> create database wordpress;
Query OK, 1 row affected (0.00 sec)

mysql> ^DBye
root@1a30f24af976:/# exit

2、php部分处理

运行镜像并挂载相关文件

docker run -p 9000:9000 --name php -v /wordpress/www:/var/www/html --privileged=true -d --link mysql php:7.1-fpm

进入php容器配置连接数据库

[root@Docker01 ~]# docker exec -it php bash
root@0ea3e8333eb3:/var/www/html# cd /usr/local/bin/
root@0ea3e8333eb3:/usr/local/bin# ./docker-php-ext-install pdo_mysql    #安装mysql相关扩展
root@0ea3e8333eb3:/usr/local/bin# ./docker-php-ext-install mysqli
root@0ea3e8333eb3:/usr/local/bin# cd /usr/local/etc/php
root@0ea3e8333eb3:/usr/local/etc/php# mv php.ini-production php.ini
root@0ea3e8333eb3:/usr/local/etc/php# echo extension=mysqli >> php.ini
root@0ea3e8333eb3:/usr/local/etc/php# echo extension=pdo_mysql >> php.ini
root@0ea3e8333eb3:/usr/local/etc/php# exit
[root@Docker01 ~]# docker restart php
php

3、nginx部分处理

运行镜像并挂载相关文件

docker run -p 80:80 --name nginx -v /wordpress/www:/usr/share/nginx/html -v /wordpress/nginx/conf.d:/etc/nginx/conf.d --privileged=true --link php -d nginx:1.14.2

在宿主机编写配置文件

[root@Docker01 ~]# cat /wordpress/nginx/conf.d/default.conf
server {
    listen  80 default_server;
    server_name localhost;
    root   /usr/share/nginx/html;
 
    location / {
        index index.php index.html index.htm;
        autoindex off;
    }
    location ~ \.php(.*)$ {
        root   /var/www/html/;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_split_path_info ^((?U).+\.php)(/?.+)$;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
        include  fastcgi_params;
    }
}

重启nginx服务

[root@Docker01 ~]# docker restart nginx
nginx

4、准备代码文件并部署

[root@Docker01 www]# ls
index.php             wp-includes
license.txt           wp-links-opml.php
readme.html           wp-load.php
wp-activate.php       wp-login.php
wp-admin              wp-mail.php
wp-blog-header.php    wp-settings.php
wp-comments-post.php  wp-signup.php
wp-config-sample.php  wp-trackback.php
wp-content            xmlrpc.php
wp-cron.php
[root@Docker01 www]# docker inspect mysql|grep IPAddress
            "SecondaryIPAddresses": null,
            "IPAddress": "172.17.0.2",
                    "IPAddress": "172.17.0.2",

部署的时候注意连接数据库的IP这里即可

这里可能是没权限,手动操作下即可 

配置好后改下属主属组,不然连文章都没法正常发,最好是统一下nginx和php的用户,这样在代码文件改成同一的用户即可,必须进容器修改代码文件的属主属组,我这边图方便,就改成777权限了

[root@Docker01 www]# chmod 777 -R *

经过测试发现草稿箱可上传,但是预然和发布后就显示404了,估计也是没有权限的问题。

5、用户统一问题

需要将nginx,php的启动用户,与代码的属主属组统一

#修改nginx配置文件的用户,可以在容器外sed修改
[root@Docker01 www]# docker exec -it nginx sed -ri /user/s#nginx#www#g /etc/nginx/nginx.conf

#修改php配置文件的用户,可以安装vim
root@0ea3e8333eb3:/var/www/html# apt-get update
root@0ea3e8333eb3:/var/www/html# apt-get install vim
root@0ea3e8333eb3:/var/www/html# cat /usr/local/etc/php-fpm.d/www.conf|grep www
...
[www]
user = www
group = www
...

#修改nginx和php代码文件的属组属主
root@be9b023a1122:/# groupadd -g666 www  
root@be9b023a1122:/# useradd -u666 -g666 www
root@be9b023a1122:/usr/share/nginx/html# chown -R www.www *

root@0ea3e8333eb3:/var/www/html# groupadd -g666 www
root@0ea3e8333eb3:/var/www/html# useradd -u666 -g666 www
root@0ea3e8333eb3:/var/www/html# chown -R www:www *

经过测试,统一用户后成功了。。。


我是koten,10年运维经验,持续分享运维干货,感谢大家的阅读和关注!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我是koten

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值