# ENTRYPOINT指令: 容器启动的时候执行的初始命令,不能被替换,如果同时使用CMD和ENTRYPOINT,cmd命令将作为ENTRYPOINT命令的参数
# (1) 使用kod:v2起一个容器,默认执行CMD ["/bin/bash","/init.sh"]
[root@docker01 kod]# docker run -d -p 80:80 kod:v2
# (2) 查看docker容器
[root@docker01 kod]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d491607b7fdc kod:v2 "/bin/bash /init.sh" 6 hours ago Up 6 hours 0.0.0.0:80->80/tcp, :::80->80/tcp crazy_mcnulty
# (3) 使用kod:v2再起一个容器,后面跟一个ls命令,这个恢复覆盖dockerfile中的CMD ["/bin/bash","/init.sh"],然后报错
[root@docker01 kod]# docker run -d -p 80:80 kod:v2 ls
b28215940f7b1a6f6bf83c0d4004a2ef12f33be898d5f2ad367d630068ad26bb
docker: Error response from daemon: driver failed programming external connectivity on endpoint amazing_volhard (4bea963d96613aa5d09355f3276ac87837ee9b1b805ad44efa754c3ba2be3910): Bind for 0.0.0.0:80 failed: port is already allocated.
[root@docker01 kod]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
b28215940f7b kod:v2 "ls" 6 seconds ago Created amazing_volhard
d491607b7fdc kod:v2 "/bin/bash /init.sh" 6 hours ago Up 6 hours 0.0.0.0:80->80/tcp, :::80->80/tcp crazy_mcnult
# 要是避免上面的情况发生,可以使用ENTRYPOINT指令
# (1) 如果这时使用ENTRYPOINT指令代替CMD指令,如果起一个容器的话,后面最后的命令不会覆盖,而是会当作ENTRYPOINT的一个参数
[root@docker01 ~]# cd /opt/dockerfile/centos7_sshd
# (2) 修改dockerfile
[root@docker01 centos7_sshd]# cat dockerfile
FROM centos:7
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
RUN yum install openssh-server initscripts -y
RUN /usr/sbin/sshd-keygen
COPY init.sh /init.sh
ENV SSH_PASS 123
ENTRYPOINT ["/bin/bash","/init.sh"]
# (3) 修改init.sh脚本
[root@docker01 centos7_sshd]# cat init.sh
#!/bin/bash
SSH_PASS=$1
echo "$SSH_PASS" | passwd --stdin root
# (4) 执行dokerfile制作镜像
[root@docker01 centos7_sshd]# docker build -t centos7_sshd:v3 .
[root@docker01 centos7_sshd]# docker run -d -p 2023:22 centos7_sshd:v3 123456
# (5) COMMAND列的值为"/bin/bash /init.sh 123456",其中123456当作一个参数传到了/init.sh当中
[root@docker01 centos7_sshd]# docker ps --no-trunc
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f8d188c56eae24081e07f6dbddb573b3399f4ccd265b3a4c4423c68df314128c centos7_sshd:v3 "/bin/bash /init.sh 123456" 30 seconds ago Up 29 seconds 0.0.0.0:2023->22/tcp, :::2023->22/tcp pedantic_goldstine
# (6) 连接测试,正确密码为123456
[root@docker01 centos7_sshd]# ssh [email protected] -p 2023
# (1) docker_centos7.tar.gz是centos7的基础镜像,docker_nginx.tar.gz是再centos基础上安装nginx服务
[root@docker02 mnt]# ls
docker_centos7.tar.gz docker_nginx.tar.gz
# (2) 查看镜像,目前系统无镜像
[root@docker02 mnt]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
# (3) 先加载docker_nginx.tar.gz镜像到系统中,可以看到一共有两层镜像
[root@docker02 mnt]# docker load -i docker_nginx.tar.gz
174f56854903: Loading layer 211.7MB/211.7MB
b023aee6d1db: Loading layer 287.6MB/287.6MB
Loaded image: centos7_nginx:v1
# (4) 查看镜像
[root@docker02 mnt]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
centos7_nginx v1 8ef62bd3235f 9 days ago 491MB
# (5) 继续导入docker_centos7.tar.gz,因为docker分层可以复用,所以这时没有导入镜像,而是复用了镜像层
[root@docker02 mnt]# docker load -i docker_centos7.tar.gz
Loaded image: centos:7
===========================================================================
# (6) 删除镜像centos7_nginx:v1,结果可以看出镜像层可以复用
[root@docker02 mnt]# docker rmi centos7_nginx:v1
Untagged: centos7_nginx:v1
## 这一层是镜像id
Deleted: sha256:8ef62bd3235fb0e90c9bddb2f128bc55109842929213ba1e3f9f7e6fd8873654
## 这一层是nginx服务层,因为centos7有镜像再用,所以不能删除,体现了镜像层可以复用,节省空间
Deleted: sha256:74b785adb2f1685629c12abff1abdaffe18dab699598ab491a7d4c96f1ffc668
/var/lib/docker/image # 这个目录只存镜像的标签,镜像的信息
/var/lib/docker/overlay2 # 实际的镜像文件存放这里
常用命令:
# (1) 查看镜像属性
docker image inpect nginx:latest
# (2) 查看镜像的历史操作
docker image history nginx:latest
# (3) 详细查看镜像的历史操作
docker image history nginx:latest --no-trunc
(1)使用体积小的镜像alpine
# linux发行版:软件包不一样,配置的路径也不一样
centos: yum
suse: zypper
ubuntu: apt-get
alpine: apk
# 使用alpine安装nginx,来说明制作的镜像体积小
[root@docker01 ~]# docker run -it -p 80:80 alpine:3.9
# alpine的镜像源为:https://mirrors.tuna.tsinghua.edu.cn/help/alpine/
# 已进入容器,在终端输入以下命令以替换TUNA镜像源:
/ # sed -i 's/dl-cdn.alpinelinux.org/mirrors.tuna.tsinghua.edu.cn/g' /etc/apk/repositories
# 查看镜像源
/ # cat /etc/apk/repositories
http://mirrors.tuna.tsinghua.edu.cn/alpine/v3.9/main
http://mirrors.tuna.tsinghua.edu.cn/alpine/v3.9/community
# 下载nginx
/ # apk add nginx
/ # mkdir /run/nginx/
# 启动nginx
/ # nginx
# 创建站点目录,并创建index.html
/ # mkdir /html/
/ # echo "hello world" >/html/index.html
# 修改nginx配置文件,然后reload
/ # cat /etc/nginx/conf.d/default.conf
server {
listen 80 default_server;
listen [::]:80 default_server;
# Everything is a 404
location / {
index index.html;
root /html;
}
}
/ # nginx -s reload
# 浏览器验证没有问题,退出容器,然后把容器提交为镜像
[root@docker01 ~]# docker commit 692fdc0604cc alpine_nginx:v1
# 查看镜像,明显看出alpine_nginx比centos7_nginx小了很多
[root@docker01 ~]# docker images
alpine_nginx v1 757e895939b7 2 seconds ago 8.29MB
centos7_nginx v3 df6c677eb8e9 4 days ago 491MB
# 小总结:
alpine优点:体积小 ,alpine缺点:有些软件系统不兼容
# 原因:
centos: 编译器 gcc glibc jdk.rpm jdk.tar.gz
alpine: 编译器 musl libc
debian/ubuntu也是使用的glibc标准库 centos也是
所以如果按体积小的方便都兼容的情况下可以依次考虑: alpine debian/ubuntu centos
(2)尽可能的清理无用的缓存文件
# (1) 将RUN指令合并再一起,并且清理yum缓存,分层减少并且磁盘空间也减少
[root@docker01 kod]# vim dockerfile
FROM centos:7
RUN curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
curl -o /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo && \
yum install nginx php-fpm php-gd php-mbstring unzip -y && \
rm -rf /var/cache/yum/*
ADD www.conf /etc/php-fpm.d/www.conf
ADD nginx.conf /etc/nginx/nginx.conf
RUN mkdir /code
COPY kodexplorer4.40.zip /code
WORKDIR /code
RUN unzip kodexplorer4.40.zip && \
chmod -R 777 /code && \
rm -rf kodexplorer4.40.zip && \
chown -R nginx:nginx .
ADD init.sh /init.sh
EXPOSE 80
VOLUME /code
CMD ["/bin/bash","/init.sh"]
# (2) 修改完dockerfile之后,执行dockerfile制作镜像
[root@docker01 kod]# docker build -t kod:v3 .
# (3) 查看镜像的大小
[root@docker01 kod]# docker images | grep kod
kod v3 cdd2f1bd8e76 2 minutes ago 369MB
kod v2 5e258095a1cd 5 days ago 677MB
kod v1 f671d94334db 6 days ago 894MB
# (4) 查看对比kod:v3和kod:v2的构建过程
[root@docker01 kod]# docker image history kod:v2
IMAGE CREATED CREATED BY SIZE COMMENT
5e258095a1cd 5 days ago CMD ["/bin/bash" "/init.sh"] 0B buildkit.dockerfile.v0
<missing> 5 days ago VOLUME [/code] 0B buildkit.dockerfile.v0
<missing> 5 days ago EXPOSE map[80/tcp:{}] 0B buildkit.dockerfile.v0
<missing> 5 days ago ADD init.sh /init.sh # buildkit 46B buildkit.dockerfile.v0
<missing> 5 days ago RUN /bin/sh -c chown -R nginx:nginx . # buil… 46.4MB buildkit.dockerfile.v0
<missing> 5 days ago RUN /bin/sh -c chmod -R 777 /code # buildkit 46.4MB buildkit.dockerfile.v0
<missing> 5 days ago RUN /bin/sh -c unzip kodexplorer4.40.zip # b… 32.5MB buildkit.dockerfile.v0
<missing> 5 days ago WORKDIR /code 0B buildkit.dockerfile.v0
<missing> 5 days ago COPY kodexplorer4.40.zip /code # buildkit 13.9MB buildkit.dockerfile.v0
<missing> 5 days ago RUN /bin/sh -c mkdir /code # buildkit 0B buildkit.dockerfile.v0
<missing> 5 days ago ADD nginx.conf /etc/nginx/nginx.conf # build… 652B buildkit.dockerfile.v0
<missing> 5 days ago ADD www.conf /etc/php-fpm.d/www.conf # build… 10kB buildkit.dockerfile.v0
<missing> 5 days ago RUN /bin/sh -c yum install nginx php-fpm ph… 334MB buildkit.dockerfile.v0
<missing> 5 days ago RUN /bin/sh -c curl -o /etc/yum.repos.d/epel… 21.1kB buildkit.dockerfile.v0
<missing> 5 days ago RUN /bin/sh -c curl -o /etc/yum.repos.d/Cent… 2.52kB buildkit.dockerfile.v0
<missing> 22 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 22 months ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 22 months ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
[root@docker01 kod]# docker image history kod:v3
IMAGE CREATED CREATED BY SIZE COMMENT
cdd2f1bd8e76 5 minutes ago CMD ["/bin/bash" "/init.sh"] 0B buildkit.dockerfile.v0
<missing> 5 minutes ago VOLUME [/code] 0B buildkit.dockerfile.v0
<missing> 5 minutes ago EXPOSE map[80/tcp:{}] 0B buildkit.dockerfile.v0
<missing> 5 minutes ago ADD init.sh /init.sh # buildkit 46B buildkit.dockerfile.v0
<missing> 5 minutes ago RUN /bin/sh -c unzip kodexplorer4.40.zip && … 46.4MB buildkit.dockerfile.v0
<missing> 5 minutes ago WORKDIR /code 0B buildkit.dockerfile.v0
<missing> 5 minutes ago COPY kodexplorer4.40.zip /code # buildkit 13.9MB buildkit.dockerfile.v0
<missing> 5 minutes ago RUN /bin/sh -c mkdir /code # buildkit 0B buildkit.dockerfile.v0
<missing> 5 minutes ago ADD nginx.conf /etc/nginx/nginx.conf # build… 652B buildkit.dockerfile.v0
<missing> 5 minutes ago ADD www.conf /etc/php-fpm.d/www.conf # build… 10kB buildkit.dockerfile.v0
<missing> 5 minutes ago RUN /bin/sh -c curl -o /etc/yum.repos.d/Cent… 105MB buildkit.dockerfile.v0
<missing> 22 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
<missing> 22 months ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
<missing> 22 months ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
(3) 修改dockerfile的时候,尽可能把修改的内容放在最后
修改dockerfile的时候,尽可能把修改的内容放在最后原因是前面的内容不用重新执行,直接走缓存
(4) 使用.dockerignore忽略构建docker镜像时,不需要的文件
dockerfile再同一个目录下的文件,如果没用的话,不要放当前目录
因为docker build的时候,会把当前目录下所有的文件都传给docker服务端,都在内存中,
有用的就用,没用的就从内存中清理掉,这个过程耗费了时间。或者创建一个文件.dockerignore
把不使用的文件名称写到这里面,一行一个文件名,这里面写的文件就不会传到服务端
但是的有的时候不得不放(gitee项目搜cms),使用dockerfile文件和项目再一起的时候,需要使用.dockerignore
忽略一些跟制作镜像无关的文件,比如readme.md
容器之间的通讯面临的问题 :
容器按顺序分配,虽然容器与容器之间默认网络的通的,但是重启容器,容器的ip地址可能发生改变 ,不知道要通讯的容器ip地址是多少? 这个可以使用--link
参数来解决这个问题。docker run --link 正在运行容器的名字(单方向)
(1) 说明--link
的作用以及原理
# (1) 使用alpine:3.9启动一个新容器,给容器起一个名称web01
[root@docker01 kod]# docker run -it --name web01 alpine:3.9
/ #
# (2) 再使用alpine:3.9启动一个容器,并且ping web01, web01:test,test是别名
[root@docker01 ~]# docker run -it --link web01:test alpine:3.9
/ # ping web01
PING web01 (172.17.0.2): 56 data bytes
64 bytes from 172.17.0.2: seq=0 ttl=64 time=0.178 ms
64 bytes from 172.17.0.2: seq=1 ttl=64 time=0.178 ms
/ # cat /etc/hosts
172.17.0.2 test e18bb8041b72 web01
172.17.0.3 aeadd7376cf2
(2) 实验演练
# 传入镜像文件
[root@docker01 zabbix]# ls
docker-mysql-5.7.tar.gz zabbix-java-gateway.tar.gz zabbix-server-mysql.tar.gz zabbix-web-nginx-mysql.tar.gz
[root@docker01 zabbix]# for n in `ls *.tar.gz`;do docker load -i $n;done
# 导入镜像
[root@docker01 zabbix]# 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" \
-d mysql:5.7 \
--character-set-server=utf8 --collation-server=utf8_bin
# 启动容器
[root@docker01 zabbix]# docker run --name zabbix-java-gateway -t \
-d zabbix/zabbix-java-gateway:latest
[root@docker01 zabbix]# 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" \
--link mysql-server:mysql \
--link zabbix-java-gateway:zabbix-java-gateway \
-p 10051:10051 \
-d zabbix/zabbix-server-mysql:latest
[root@docker01 zabbix]# docker run --name zabbix-web-nginx-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" \
--link mysql-server:mysql \
--link zabbix-server-mysql:zabbix-server \
-p 80:80 \
-d zabbix/zabbix-web-nginx-mysql:latest
docker-compose: 批量管理一组容器批量管理容器叫容器编排
docker-compose可以批量启动,批量关闭,批量重启容器
docker-compose只是一个工具,通过调用docker来实现对容器的管理
docker-compose容器默认都是后台启动
docker-compose安装:yum install docker-compose -y
(需要epel源)
常用命令:
docker-compose up -d # 创建并启动一组容器(-d在后台启动)
docker-compose down # 停止并删除一组容器
docker-compose start # 批量启动(后面跟容器名称,可以启动一个容器)
docker-compose stop # 批量停止(后面跟容器名称,可以停止一个容器)
docker-compose restart # 批量重启
docker-compose scale # 启动多个相同容器
小提示:
docker-compose不用使用--link
,因为docker-compose直接可以通过容器的名字进行通讯,内部有dns解析。不用在使用--link
,--link
是单向的,docker-compose是双向的,所以在docker-compose里面不用考虑--link
。
docker logs 容器名称
实时看日志
实战演练:
(1)使用docker-compose来管理zabbix容器
# (1) 配置yum源,安装docker-compose
[root@docker01 ~]# curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo && \
[root@docker01 ~]# curl -o /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo
[root@docker01 ~]# yum install docker-compose -y
# (2) 创建目录,编写docker-compose.yml
[root@docker01 ~]# mkdir -p /opt/docker-compose/zabbix
[root@docker01 ~]# cd /opt/docker-compose/zabbix
[root@docker01 zabbix]# cat docker-compose.yml
version: '3'
services:
mysql-server:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: root_pwd
MYSQL_DATABASE: zabbix
MYSQL_USER: zabbix
MYSQL_PASSWORD: zabbix_pwd
command: --character-set-server=utf8 --collation-server=utf8_bin
zabbix-java-gateway:
image: zabbix/zabbix-java-gateway:latest
restart: always
zabbix-server:
depends_on:
- mysql-server
image: zabbix/zabbix-server-mysql:latest
restart: always
environment:
DB_SERVER_HOST: mysql-server
MYSQL_DATABASE: zabbix
MYSQL_USER: zabbix
MYSQL_PASSWORD: zabbix_pwd
MYSQL_ROOT_PASSWORD: root_pwd
ZBX_JAVAGATEWAY: zabbix-java-gateway
ports:
- "10051:10051"
zabbix-web-nginx-mysql:
depends_on:
- zabbix-server
image: zabbix/zabbix-web-nginx-mysql:latest
ports:
- "80:80"
restart: always
environment:
DB_SERVER_HOST: mysql-server
MYSQL_DATABASE: zabbix
MYSQL_USER: zabbix
MYSQL_PASSWORD: zabbix_pwd
MYSQL_ROOT_PASSWORD: root_pwd
# (3) 使用docker-compose批量启动一组容器,使用浏览器访问进行验证
# 批量启动一组容器,docker-compose会自动寻找当前目录下的docker-compose.yml
[root@docker01 zabbix]# docker-compose up -d
# 查看容器的运行状态
[root@docker01 zabbix]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
e8335321925b zabbix/zabbix-web-nginx-mysql:latest "/bin/bash /run_zabb…" 5 seconds ago Up 4 seconds 0.0.0.0:80->80/tcp, :::80->80/tcp, 443/tcp zabbix_zabbix-web-nginx-mysql_1
f52e728c1856 zabbix/zabbix-server-mysql:latest "/bin/bash /run_zabb…" 5 seconds ago Up 4 seconds 162/udp, 0.0.0.0:10051->10051/tcp, :::10051->10051/tcp zabbix_zabbix-server_1
783f5dd889f9 mysql:5.7 "docker-entrypoint.s…" 6 seconds ago Up 4 seconds 3306/tcp zabbix_mysql-server_1
f8c6ce80f625 zabbix/zabbix-java-gateway:latest "/bin/bash /run_zabb…" 6 seconds ago Up 4 seconds 10052/tcp zabbix_zabbix-java-gateway_1
[root@docker01 zabbix]#
# 补充:使用docker-compose在启动一个容器服务(注意相同镜像的容器宽口可能冲突,下面演示的不会冲突)
[root@docker01 zabbix]# docker-compose scale zabbix-java-gateway=2
(2)使用docker-compose来管理wordpress容器
# (1) 手动启动容器
docker run --name mysql-wp -it \
-e MYSQL_DATABASE="wordpress" \
-e MYSQL_USER="blog" \
-e MYSQL_PASSWORD="blog" \
-e MYSQL_ROOT_PASSWORD="root_pwd"
-d mysql:5.7 \
--character-set-server=utf8 --collation-server=utf8_bin
docker run --name wordpress -p 81:80 --link mysql-wp:mysql -e WORDPRESS_DB_HOST=mysql \
-e WORDPRESS_DB_USER=blog -e WORDPRESS_DB_PASSWORD=blog -e wordpress:latest
# (1) 利用上面手动启动容器的方法,改写成docker-compose.yml, 用docker-compose进行管理
[root@docker01 ~]# mkdir -p /opt/docker-compose/wordpress
[root@docker01 ~]# cd /opt/docker-compose/wordpress
# 导入镜像文件
[root@docker01 wordpress]# docker load -i docker_wordpress-latest.tar.gz
[root@docker01 wordpress]# cat docker-compose.yml
version: '3'
services:
mysql:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: root_pwd
MYSQL_DATABASE: wordpress
MYSQL_USER: blog
MYSQL_PASSWORD: blog
command: --character-set-server=utf8 --collation-server=utf8_bin
wordpress:
depends_on:
- mysql
image: wordpress:latest
ports:
- "81:80"
restart: always
environment:
WORDPRESS_DB_HOST: mysql
WORDPRESS_DB_USER: blog
WORDPRESS_DB_PASSWORD: blog
(3) 使用docker-compose启动wordpress,并启动浏览器访问http://10.0.0.11:81
[root@docker01 wordpress]# docker-compose up -d
[root@docker01 wordpress]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
55abb47c9f65 wordpress:latest "docker-entrypoint.s…" 4 seconds ago Up 4 seconds 0.0.0.0:81->80/tcp, :::81->80/tcp wordpress_wordpress_1
2f000ef0cdc9 mysql:5.7 "docker-entrypoint.s…" 5 seconds ago Up 4 seconds 3306/tcp wordpress_mysql_1