一、Docker介绍
1.1 什么是docker?
docker是容器技术的一种,容器技术是一种轻量级的虚拟化方案,我们可以使用docker创建容器,容器与传统的虚拟机类似,只是更加轻量级,更加方便使用。
Docker的英文翻译是”搬运工“的意思,他搬运的东西就是我们常说的集装箱/容器Container,Container 里面装的是任意类型的App。
强调:一定要区分开docker与容器,docker是一个软件用来创建容器的,docker不是容器。
1.2 docker的追求
1、轻量级 2、可移植性 docker追求将app变成标准化、可移植、自管理的组件 可以在任意主流操作系统中开发、调试、运行
1.3 docker架构
Docker Engine简称Docker 主要包含下面几个组件;
常驻后台进程Dockerd一个用来和Dockerd交互的REST API Server命令行CLI接口,通过和REST API进行交互
Docker整体架构由以下三部分构成,采用的是C/S体系架构:
- 1、Docker客户端
- 2、Docker主机/服务端
- 2.1 docker daemon守护进程
- 2.2 从镜像仓库pull拉到本地的镜像
- 2.3 在本地通过镜像启动的容器
- 3、远程镜像仓库
Docker守护进程常驻后台负责构建,运行和分发Docker容器。
Docker客户端和守护进程可以在同一个系统上运行,也可以将Docker客户端连接到远程Docker守护进程。Docker客户端和守护进程使用REST API通过UNIX套接字或网络接口进行通信。
二、安装docker
2.1 准备环境
1)关闭selinux
# 永久关闭 sed -i 's#enforcing#disabled#g' /etc/selinux/config #临时关闭 setenforce 0
2)关闭防火墙
systemctl disable --now firewalld
3)关闭swap分区
# 关闭swap分区,至于为何要关闭swap,在后续介绍cgroup时会详细介绍 swapoff -a # 注释swap分区 vim /etc/fstab
2.2 安装
1)卸载之前的docker
yum remove docker docker-common docker-selinux docker-engine -y
2)安装docker所需安装包
yum install -y yum-utils device-mapper-persistent-data lvm2
3)安装docker yum源
yum install wget -y # 官方源(国内访问不了了) wget -O /etc/yum.repos.d/docker-ce.repo https://repo.huaweicloud.com/docker-ce/linux/centos/docker-ce.repo # 可以用阿里云的(与官网的是一致的,感谢阿里云) yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
4)安装docker
# 1、安装 yum install docker-ce -y systemctl start docker # 启动后,才会创建出目录/etc/docker # 2、修改配置 vim /etc/docker/daemon.json # 修改文件时记得去掉下面的注释 { # 1、cgroup驱动,在介绍cgroup机制时会详细介绍 "exec-opts": ["native.cgroupdriver=systemd"], # 2、由于国内特殊的网络环境,往往我们从Docker Hub中拉取镜像并不能成功,而且速度特别慢。那么我们可以给Docker配置一个国内的registry mirror,当我们需要的镜像在mirror中则直接返回,如果没有则从Docker Hub中拉取。是否使用registry mirror对Docker用户来说是透明的。 "registry-mirrors":["https://reg-mirror.qiniu.com/"], # 3、# 修改数据的存放目录到/opt/mydocker/,原/var/lib/docker/ # 3.1 老版本docker-ce指定数据目录用graph # "graph": "/opt/mydocker", # 3.2 docker20.x.x新版本不用graph,而是用data-root # "data-root": "/opt/mydocker", # 4、重启docker服务,容器全部退出的解决办法 "live-restore": true }
qiniu的镜像加速器如果很慢,你可以使用阿里的
访问如下地址,扫码进入
https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
5)启动并设置开机自启
先创建出数据目录 [root@docker01 ~]# mkdir -p /opt/mydocker [root@docker01 ~]# systemctl restart docker.service [root@docker01 ~]# systemctl enable --now docker.service [root@docker01 ~]# docker info # 查看
三、镜像pull与push
容器内的“系统”来源于镜像,镜像需要从镜像仓库里下载,后续我们部署自己的镜像仓库,作为开始先用官方仓库docker hub,,Docker之所以能这么快的火起来,和Docker Hub的作用是分不开的。Docker构建了像GitHub一样的仓库,用来存放大家构建好的Docker镜像,其中已经包括了15000的镜像。大部分需求,都可以通过在Docker Hub中直接下载镜像来实现。
ps:docker Hub是一个平台,平台里有很多仓库(可以理解为文件夹),仓库分为公共的仓库(大家都知道的一个大文件夹),每个注册的用户也可以有自己的仓库(相当于每个用户自己的文件夹),仓库里包含的一系列镜像(相当于文件夹下的文件),镜像有公开与私有之分,公开的镜像大家无需登录验证就可以下载,而私有镜像只能在登录验证通过后才能下载。
1、从公共仓库下载镜像
# 直接写镜像名字,那默认会从我们配置的registry-mirrors拉取镜像,没有则去docker hub里拉取 docker search nginx # 搜索镜像 docker pull nginx:1.18 # 从默认仓库里拉取镜像,如果是公开镜像则无需登录即可拉取,如果是私有镜像则需要先登录docker hub才能拉取 docker images # 查看
2、在docker hub界面里注册一个自己的仓库,在仓库egonlin下创建一个公开镜像与一个私有镜像
Docker Hub官方地址:https://hub.docker.com/
同上,再创建一个公开的镜像Repository
3、登录与登出
拉取私有镜像或上传镜像到某个镜像仓库里,都需要事先登录该镜像仓库
需要强调一点是web界面操作的地址是https://hub.docker.com/,而仓库地址是docker.io
# 显示Login Succeeded代表登录成功,登录成功后信息存放在当前用户家目录下,例如/root/.docker/config.json docker login -u egonlin -p 'xxx' docker.io # 登出 docker logout
4、往仓库egonlin上传镜像
# 1、本地有一个镜像,准备上传到镜像仓库里 [root@test03 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx 1.18 c2c45d506085 15 months ago 133MB # 2、先打标签,标签里包含你要上传的仓库名字与镜像tag [root@test03 ~]# docker tag nginx:1.18 egonlin/private_nginx:1.18 [root@test03 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE nginx 1.18 c2c45d506085 15 months ago 133MB egonlin/private_nginx 1.18 c2c45d506085 15 months ago 133MB # 3、上传,没有指定仓库的地址,则默认地址为docker.io [root@test03 ~]# docker push egonlin/private_nginx:1.18 # 传到docker.io/egonlin/private_nginx:1.18 # 同上步骤,再传一个 docker tag nginx:1.18 egonlin/prublic_nginx:1.18 docker push egonlin/prublic_nginx:1.18
5、从仓库egonlin里下载镜像
# 登出 [root@test03 ~]# docker logout Removing login credentials for https://index.docker.io/v1/ # 下载公开镜像,不需要登录 [root@test03 ~]# docker pull egonlin/public_nginx:1.18 # 下载私有镜像,没有登录会报权限问题,如下 [root@test03 ~]# docker pull egonlin/private_nginx:1.18 ... repository does not exist or may require 'docker login': denied: requested access to the resource is denied [root@test03 ~]# docker login -u egonlin -p 'xxx' docker.io [root@test03 ~]# docker pull egonlin/private_nginx:1.18
6、镜像save与load
如果我们有这么一个需求,你的同事想要你机器上的镜像,但是你同事的电脑没有网络,所以即便你可以把你本地的镜像上传到镜像仓库里但是你同事是没办法拉取的,怎么办?
可以将你的本地镜像save成一个文件,然后用ftp或者u盘之类的工具拷贝给你同事,你同事在机器上load导入即可
# 在本地save镜像 docker save nginx:1.8 -o 1.tar # 你同事拿到1.tar后,直接导入即可 docker load -i 1.tar # 如果我们想查看镜像里都是写啥,很明显你解压1.tar就行 mkdir /test tar xmf 1.tar -C /test
四、容器常用操作
# 后台启动 docker run -d --name test egonlin/private_nginx:1.18 # 查看 docker container ls docker inspect 容器ID号 # 进入容器 docker exec -ti test sh # 停止与启动 docker stop test docker container ls -a # 停止后,可以加-a参数查看 docker start test docker restart test # 删除 docker container rm -f test # 交互式方式启动, 会执行sh命令进入交互式环境,--rm参数的意思是在exit退出后容器自动删除 docker run -ti --rm --name test egonlin/private_nginx:1.18 sh # 指定命令启动,如sleep 1000 docker pull centos:7 docker container run -d --name test1 centos:7 sleep 1000 # 本地文件拷贝到容器(了解即可) docker container cp /tmp/a.txt test:/usr/share/nginx/html/a.txt # 容器test的文件拷贝到本地(了解即可) docker container cp test:/usr/share/nginx/html/a.txt /tmp/ # "live-restore": true 如果配置文件没有指定上述参数,那么可以在run启动容器时指定--restart=always 重启docker服务后,容器跟着一起重启,不设置的话,服务重启容器则关闭 插一个了解的小知识: Docker退出容器不关闭容器的方法 docker 以交互式的方式启动容器后,如果使用exit退出交互界面后,整个容器都会exit 。但是如何使我们退出交互模式的同时不关闭容器呢,那就是在要退出交互模式时不使用exit还是使用命令 Ctrl+P+Q 。
常用命令汇总
单机千个左右的容器 谷歌每天上万十几万个容器销毁 # 1、基础类的 docker search docker login -u admin -p xxxxx 镜像仓库地址:端口 # 2、镜像相关 docker image ls ****** ls -q # 静默输出,只输出容器的id pull push tag inspect ****** rm ****** save load # 3、容器相关 docker container run ****** start ****** stop ****** restart kill attach exec ****** ls ****** top ****** inspect ****** logs docker container rm -f `docker container ls -a -q `
五、挂载卷
容器分层
可写层:upperdir
镜像层(只读层):lowerdir
容器被删掉后,可写层的数据就没了,如果我们的需求是想要数据持久化,即便容器销毁还可以从一个地方找到数据,那么可以使用挂载卷
挂载卷有两种方式
方式一:挂载目录,使用-v参数
# 可以指定多个-v,关联多个数据卷 mkdir /test echo 111 > /test/index.html # -p后冒号分割,第一个参数代表物理机监听端口,第二个参数代表容器监听端口 docker container run -d --name test -p 8080:80 -v /test:/usr/share/nginx/html/ egonlin/private_nginx:1.18 # 查看本机ip地址,可以访问测试 http://本机ip:8080 # 删除容器后,数据依然存在于/test下
方式二:挂载卷
# 示例1 [root@test03 ~]# docker volume create test-vol test-vol [root@test03 ~]# [root@test03 ~]# [root@test03 ~]# docker volume ls DRIVER VOLUME NAME local test-vol [root@test03 ~]# docker container run -d --name test -p 8080:80 -v test-vol:/usr/share/nginx/html/ egonlin/private_nginx:1.18 [root@test03 ~]# docker exec -ti test sh # cd /usr/share/nginx/html/ # echo 666 > index.html # 数据写入了卷test-vol里,删除容器后依然存在 # 删除容器后,卷依然存在 [root@test03 ~]# docker container rm -f test test [root@test03 ~]# docker volume ls DRIVER VOLUME NAME local test-vol # 重新挂载即可 docker container run -d --name test -p 8080:80 -v test-vol:/usr/share/nginx/html/ egonlin/private_nginx:1.18 # 示例2 docker volume create mysql-volume docker volume ls docker volume inspect mysql-volume docker run -d --name abcdocker -v mysql-volume:/var/lib/mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.7 docker container exec -ti abcdocker bash # 然后进入数据库,创建库,其实创建到了mysql-volume下 然后删除容器,再启一个容器,挂载mysql-volume卷,会发现库还在 docker container rm -f abcdocker docker run -d --name test -v mysql-volume:/var/lib/mysql -e MYSQL_ALLOW_EMPTY_PASSWORD=true mysql:5.7
挂载数据卷容器(解决很多容器的-v选项都一样的问题,写起来麻烦,可以制作一个数据卷容器,然后挂载给其他容器)
步骤1:准备好数据目录 mkdir -p /test/aaa mkdir -p /test/bbb mkdir -p /test/html echo "11111" > /test/aaa/a.txt echo "22222" > /test/bbb/b.txt echo "hello egon" > /test/html/index.html 步骤2:启动数据卷容器 docker container run -d --name "nginx_volume" -v /test/aaa:/opt/a -v /test/bbb:/opt/b -v /test/html/:/usr/share/nginx/html/ centos:7 tail -f /dev/null # 末尾的命令是tail -f /dev/null是为了让容器有一个前台一直运行的命令,如果你执行的是bash这种后台执行的命令 # 那么需要把-d换成-ti,进入容器后,输入ctrl p q 步骤3:挂载 docker container run --volumes-from nginx_volume -d -p 8085:80 --name "nginx8085" egonlin/private_nginx:1.18 docker container run --volumes-from nginx_volume -d -p 8086:80 --name "nginx8086" egonlin/private_nginx:1.18 总结:在集中管理集群中,大批量的容器都需要挂载相同的多个数据卷时,可以采用数据卷容器进行统一管理
六、部署自己的镜像仓库
配置自己的docker registry
说明:此处为了让大家快速用上自己的镜像仓库,我们就直接启一个docker registry,但你要知道的是,这个registry很简陋,后期我们在学习k8s时,部署的harbor镜像仓库,Harbor 最核心的功能就是给 docker registry 添加上一层权限保护的功能。。。后续我们会详细介绍它
=========》1、启动自己的registry docker pull registry mkdir /opt/registry docker run -d -p 5000:5000 --restart=always --name registry -v /opt/registry:/var/lib/registry registry =========> 2、配置文件 cat > /etc/docker/daemon.json << EOF { "graph": "/data/docker", "storage-driver": "overlay2", "insecure-registries": ["172.16.10.14:5000"], -----------------> 增加一行,指定自己的docker仓库 "registry-mirrors": ["https://reg-mirror.qiniu.com/"], "exec-opts": ["native.cgroupdriver=systemd"], "live-restore": true } EOF systemctl restart docker ===========>3、往自定义仓库推送镜像 镜像地址格式 192.168.15.100:5000/egonlin/nginx:v1.18 两步走 先打标签 docker tag centos:7 172.16.10.14:5000/egonlin/centos:7 后推送 docker push 172.16.10.14:5000/egonlin/centos:7 ===========>4、在另外一台机器验证,pull镜像 docker pull 172.16.10.14:5000/egonlin/centos:7 ==============>5、解决安全问题,上面的无论是谁都可以pull和push了,不合理,应该有账号认证 yum install httpd-tools -y mkdir /opt/registry-auth -p htpasswd -Bbn egon 123 >> /opt/registry-auth/htpasswd 重新启动容器 docker container rm -f 容器registry的id号码 docker container run -d -p 5000:5000 -v /opt/registry-auth/:/auth -v /opt/registry:/var/lib/registry --name register-auth -e "REGISTRY_AUTH=htpasswd" -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" -e REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd registry =====================> 6、在测试机进行登录 docker login -u egon -p 123 172.16.10.14:5000 然后进行push操作
补充
# 一、问题: docker登录私有harbor,发现登陆报错; Error response from daemon:Get “https:.//.../v2/"": http: server gave HTTP response to HTTs client # 二、解决方法: 1.在服务器中,cd到docker目录下 cd /etc/docker 2.看这个目录下有没有daemon.json 这个文件,如果没有就手动创建 touch daemon.json,然后 vim daemon.json touch daemon.json vim daemon.json 3.在里面写入一个类似于json格式的键值对 { "insecure-registries":["你的harborip:端口"] } #这里填入的就是你的harbor ip地址 4.重启docker服务 Systemctl restart docker 5.然后把docker容器都起来 docker start container_name #container_name 就是你们docker里的容器名字,把他们都起来 6.现在再去登录docker harbor,即可登录成功
七、容器导出为镜像
容器分层
可写层:upperdir
镜像层(只读层):lowerdir
容器被删掉后,可写层的数据就没了,如果我们的需求是基于一个基础镜像制作一个新镜像,那么我们可以这么做,pull一个基础镜像,然后用该镜像run启动一个容器,然后exec进入容器内部署各种软件做好一些配置,这些写操作都留在了upperdir层,一旦销毁容器一切都不复存在,此时可以在容器外使用commit命令把容器整体upperdir+lowerdir导出为一个新镜像
# 1、下载基础镜像 docker pull centos:7 # 2、启动容器 docker run -d --name test111 centos:7 sleep 10000 # 3、进入容器安装、修改配置、编写启动文件 [root@test03 ~]# docker exec -ti test111 sh sh-4.2# mkdir /soft sh-4.2# echo 111 > /soft/1.txt sh-4.2# echo 222 > /soft/2.txt sh-4.2# echo "" sh-4.2# echo "echo start...;tail -f /dev/null" > /soft/run.sh sh-4.2# exit # 4、commit镜像当前运行的容器,其实就是它的upperdir+lowerdir导出为一个新镜像 [root@test03 ~]# docker commit test111 myimage:v1.0 [root@test03 ~]# docker images REPOSITORY TAG IMAGE ID CREATED SIZE myimage v1.0 adfed0daa724 4 seconds ago 204MB # 5、可以用新镜像启动容器,当然,别人拿到你的新镜像之后,也可以采取一样的步骤,在你的镜像基础上继续做它的镜像,说到这里你应该明白那么多镜像都是怎么来的,原理就是这个原理,只是后续会把上述操作都按照某个格式写到一个文件里,这个文件就是dockerfile文件,后续我们会介绍 [root@test03 ~]# docker run -d --name test222 myimage:v1.0 sh /soft/run.sh ea04adcee6d7f157f764d2c8028eb5bdfd9c02a436ba3941c87a58304e853dfa [root@test03 ~]# [root@test03 ~]# [root@test03 ~]# docker top test222 UID PID PPID C STIME TTY TIME CMD root 21349 21330 0 11:39 ? 00:00:00 sh /soft/run.sh root 21375 21349 0 11:39 ? 00:00:00 tail -f /dev/null
八、制作镜像
储备知识1
刚开始接触Docker的朋友,可能会遇到这么一个问题,使用centos7镜像创建容器后,在里面使用systemctl启动服务报错。针对这个报错,我们接下来就分析下! # docker run -itd --name centos7 centos:7 # docker attach centos7 # yum install vsftpd # systemctl start vsftpd Failed to get D-Bus connection: Operation not permitted 不能启动服务,什么情况? 难道容器不能运行服务嘛!!! 答: Docker的设计理念是在容器里面不运行后台服务,并且一个容器内最好只运行一个进程(前台运行的进程),容器的名称空间是以clone创建出的第一个进程为基础初始化而来,如果该进程结束了,容器的名称空间也就被回收了,整个容器也就结束了。 也可以间接的理解为就是容器里运行服务的应用进程。一个容器的生命周期是围绕这个主进程存在的。 再说到systemd,这个套件已经成为主流Linux发行版(比如CentOS7、Ubuntu14+)默认的服务管理,取代了传统的SystemV风格服务管理。systemd维护系统服务程序,它需要特权去会访问Linux内核。而容器并不是一个完整的操作系统,只有一个文件系统,而且默认启动只是普通用户这样的权限访问Linux内核,也就是没有特权,所以自然就用不了! 我就想这样运行,难道解决不了吗? 答:可以,以特权模式运行容器。 创建容器: # docker run -d -name centos7 --privileged=true centos:7 /usr/sbin/init 进入容器: # docker exec -it centos7 /bin/bash
制作镜像有两种方式,如下
8.1 docker commit
练习用,基本逻辑就是下载基础镜像、run起来、exec进入容器部署环境、在容器外commit将容器导出为新镜像
强调: 1、一个容器分为镜像层+可写层,对容器的修改是在可写成,修改完的内容会在容器销毁后丢失无法保存下来,可以通过下述方式 持久化保存自己的新镜像 2、每次容器启动,有且只能启动一个进程 3、启动容器时,如果命令时后台运行,即执行完毕后没有夯住,容器立即就结束了,所以需要在前台运行 制作镜像 1、启动基础镜像容器 docker image pull centos:7.9.2009 docker container run -ti --name test centos:7.9.2009 bash 2、安装所需要的软件包 yum install openssh-* -y yum install initscripts -y 3、启动ssh(首次启动会生成密钥对,不然下次启动容器时还得手动启动来生成) 4、docker commit 镜像id或名字 egonlin/myimage:v1.0 只是将镜像可写层的数据commit持久化保持下来了,进程是无法保存的(默认启动的第一个进程是init,第二个是bash) 5、基于新镜像启动容器,实现centos系统+sshd的功能,并且做好端口映射,让宿主机以外的也可以链接到 docker container run -d --name egon_test egonlin/centos7.9.2009_sshd:v1 /usr/sbin/sshd -D 如果是下面的方式启动,则启动一下容器立即结束了,所以应该用上面-D选项让其在前台运行,即不让容器结束 docker container run -d --name egon_test egonlin/centos7.9.2009_sshd:v1 /etc/init.d/sshd start docker container run -d -p 2222:22 --name yyy egonlin/myimage /usr/sbin/sshd -D ssh root@192.168.15.100 -p 2222 ===========================================centos7安装完ssh后没有/etc/init.d/sshd的问题 yum install openssh-server -y mkdir /var/run/sshd ecoh 'UseDNS no' >> /etc/ssh/sshd_config sed -i -e '/pam_loginuid.so/d' /etc/pam.d/sshd echo 'root:1' | chpasswd /usr/bin/ssh-keygen -A /usr/bin/sshd -D
构建企业镜像:制作lamp
centos7.9.2009 ssh nginx mysql php # 1、拉取基础镜像 docker image pull centos:7.9.2009 # 2、宿主机创建目录 mkdir -p /opt/vol/mysql mkdir -p /opt/vol/html # 3、用基础镜像启动容器 docker container run -ti --name one -v /opt/vol/mysql:/var/lib/mysql -v /opt/vol/html:/usr/share/nginx/html centos:7.9.2009 bash # 4、安装软件 yum install openssh-* mariadb mariadb-* initscripts -y yum install -y php php-devel php-fpm php-mysql php-common php-devel php-gd libjpeg* php-imap php-ldap php-odbc php-pear php-xml php-xmlrpc php-mbstring php-mcrypt php-bcmath php-mhash libmcrypt libmcrypt-devel ====>安装nginx [root@f7fe79b795a3 /]# cat /etc/yum.repos.d/nginx.repo [nginx-stable] name=nginx stable repo baseurl=http://nginx.org/packages/centos/7/x86_64/ gpgcheck=1 enabled=1 gpgkey=https://nginx.org/keys/nginx_signing.key module_hotfixes=true [root@f7fe79b795a3 /]# yum install nginx -y # 5、初始化软件 ## 初始化ssh /etc/init.d/sshd start echo 123 | passwd root --stdin ## 初始化mysql /usr/bin/mysql_install_db chown -R mysql.mysql /opt/vol/mysql/ /usr/bin/mysqld_safe --user=mysql & grant all on *.* to root@'%' identified by '123'; grant all on *.* to discuz@'%' identified by '123'; create database discuz charset utf8mb4; ## 启动php-fpm /usr/sbin/php-fpm & ## 启动nginx nginx cat /etc/nginx/conf.d/default.conf server { listen 80; server_name localhost; #access_log /var/log/nginx/host.access.log main; location / { root /usr/share/nginx/html; index index.php; } location ~ \.php$ { root /usr/share/nginx/html; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } error_page 500 502 503 504 /50x.html; location = /50x.html { root /usr/share/nginx/html; } } nginx -s reload # 6、制作第一版镜像 docker commit one egonlin/one # 7、根据第一版镜像启动容器 docker container run -p 8080:80 -ti --name two -v /opt/vol/mysql:/var/lib/mysql -v /opt/vol/html:/usr/share/nginx/html egonlin/one bash # 8、启动新容器中的服务 /etc/init.d/sshd start mysqld_safe --user=mysql & nginx # 9、编写php页面,测试功能 cat >> /usr/share/nginx/html/index.php << EOF <?php phpinfo(); ?> EOF # 10、上传论坛代码到/usr/share/nginx/html的对应目录/opt/vol/html下 把upload目录改为bbs好听 cp -r upload/ /usr/share/nginx/html/bbs # 11、制作新镜像,退出的容器也可以制作 docker commit two egonlin/three # 12、容器只能启动一个前台进程,若想启动多个,需要写脚本,启容器时执行脚本即可,脚本只要能够夯住就可以了 cat >> /opt/vol/html/init.sh << EOF #!/bin/bash /usr/sbin/php-fpm & nginx /usr/bin/mysqld_safe --user=mysql & /usr/sbin/sshd -D EOF chmod +x /opt/vol/html/init.sh # 13、启动容器,映射端口、自动启动多个服务 docker container run -d --name egon_bbs -p 8888:80 -p 2222:22 -p 33060:3306 -v /opt/vol/mysql:/var/lib/mysql -v /opt/vol/html:/usr/share/nginx/html egonlin/three /usr/share/nginx/html/init.sh 在客户端访问:http://192.168.15.100:8888/
8.2 dockerfile
编写dockerfile文件,这个才是推荐的方法。dockerfile基本语法如下