利用dockerfile实现自定义的web容器服务(Apache)、数据库服务(MySQl)
👉一、利用dockerfile实现自定义的web容器服务(apache)
整体思路:基于httpd:latest基础镜像,构造Apache镜像.
(1)从docker hub![]上pull基础镜像httpd
docker pull httpd
拉取最新版本的httpd镜像:
docker images
查看本地镜像列表,确认成功拉取httpd镜像:
(2)创建一个工作目录,用于存放dockerfile、配置文件及其他相关文件:
- 可以使用
mkdir 目录名
构建目录,也可以手动构建
(3)在工作目录下创建dockerfile文件,dockerfile文件内容如下:
#Base images
FROM httpd
#MAINTAINER作者信息
MAINTAINER set up by lxc(https://www.cnblogs.com/lxccccc/)
#COPY本地文件到容器中
COPY ./public-html/ /usr/local/apache2/htdocs
COPY ./myhttpd.conf /usr/local/apache2/conf/httpd.conf
#暴露端口
EXPOSE 6666
CMD ["httpd-foreground"]
(4)在文件目录下创建配置文件myhttpd.conf,作为容器的httpd配置文件:
在dockerfile中EXPOSE 6666
仅仅只是声明了暴露的端口号,要使用这个端口号监听容器还需要在配置文件中添加监听端口。如果熟悉httpd,可以直接编写其配置文件;如果对httpd不
熟悉,建议可以按照以下比较无脑的方法配置httpd文件(搁这尬住了好久,多亏老师出手相助,一语点醒梦中人)。
基本思路就是在官方配置文件的基础上再加一个监听端口,保证服务可行,具体步骤如下:
a. 首先是在官方文档中找到了存放httpd配置文件的位置/usr/local/apache2/httpd.conf
:
b. 然后启动一个httpd容器:
c. 将容器中的/usr/local/apache2/httpd.conf
拷贝到当前工作目录下,使用指令docker cp 容器ID:容器内文件目录 主机目录
:
d. 使用gedit或vim打开httpd.conf文件,在Listen 80
下方添加监听所要暴露的端口:
e. 将文件另存为myhttpd.conf:
(5)可以在工作目录下构建一个自己的html代码目录,将其拷贝到镜像中,在运行时可以显示自己的html页面:
- html存放位置:
- html内容:
<html>
<h1>Welcome to apache!</h1>
<a href="http://www.apache.org/">Welcome to apache!</a>
</html>
(6)build自己的镜像,docker build -t image:tag .
:
(7)运行容器,使用主机的端口8080和8081分别监听容器的80和6666端口,命令格式为docker run -p 主机端口:容器端口 -d image:tag
:
打开浏览器,访问0.0.0.0:8080
和0.0.0.0:8081
,可以看到,两个端口都能监听到容器,显示之前copy进去的html页面:
(ps:关于挂载主机目录到容器目录,参考docker volumn
到这里就利用dockerfile成功搭建了基于httpd的镜像,实现了自定义的web服务,下面继续介绍如何通过dockerfile构造基于MySQL的镜像。
👉二、利用dockerfile实现自定义的数据库服务(MySQL)
整体思路:基于mysql:latest基础镜像,构造MySQL镜像.
(1)从docker hub上pull mysql:latest
到本地镜像仓库:
(2)创建一个目录,用于存放制作MySQL镜像的dockerfile文件及相关文件,重点是dockerfile的构建,需要合理使用环境变量。dockerfile内容如下:
#基础镜像
FROM mysql
#作者信息
MAINTAINER by lxc(https://www.cnblogs.com/lxccccc/)
#设置root密码
ENV MYSQL_ROOT_PASSWORD 6666
#设置不可免密登录
ENV MYSQL_ALLOW_EMPTY_PASSWORD no
#创建数据库
ENV MYSQL_DATABASE docker_mysql
#为docker_mysql创建新用户,该用户被授予操作docker_mysql的所以权限
ENV MYSQL_USER=docker
ENV MYSQL_PASSWORD=123456
#将所需文件放到容器中
COPY schema.sql /mysql/schema.sql
(3)构造schema.sql文件用于建表:
-- 创建数据库
create database `docker_mysql` default character set utf8 collate utf8_general_ci;
use docker_mysql;
-- 建表
DROP TABLE IF EXISTS `myuser`;
CREATE TABLE `myuser` (
`id` bigint(20) NOT NULL,
`created_at` bigint(40) DEFAULT NULL,
`last_modified` bigint(40) DEFAULT NULL,
`email` varchar(255) DEFAULT NULL,
`first_name` varchar(255) DEFAULT NULL,
`last_name` varchar(255) DEFAULT NULL,
`username` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 设置数据库引擎和字符编码规则(UTF-8)
-- 插入数据
INSERT INTO `myuser` (`id`, `created_at`, `last_modified`, `email`, `first_name`, `last_name`, `username`)
VALUES
(0,1490257904,1490257904,'hanhan.han@example.com','hanhan','han','hanhanhan');
(4)build MySQL镜像:
(5)运行容器:
(6)在容器中进行数据库相关操作:
a. 使用root用户登录,不可免密登录
- 不使用密码登录,无法登录
- 使用密码登录,输入dockerfile中环境变量MYSQL_USER_PASSWORD设定的密码值(6666),成功登录
b. 使用root用户身份查询数据库、并利用source /mysql/schema.sql
进行建表:
c. 使用dockfile中创建的docker用户进行登录:
d. 对数据库docker_mysql 进行查表,插入数据操作:
- 查表
- 向表格中插入数据
(7)查看容器中的详细信息docker inspect 容器ID
[
{
"Id": "be5e4f7e3b6095df3f31688bbafb01b1451b525d8dcac00caab8118f6fe79e49",
"Created": "2020-04-22T12:51:47.519212013Z",
"Path": "docker-entrypoint.sh",
"Args": [
"mysqld"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 6432,
"ExitCode": 0,
"Error": "",
"StartedAt": "2020-04-22T12:51:49.506619213Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:ae911d85b87116c3107758593d228e5a9a899554c37c0b97f8dc1428a7006583",
"ResolvConfPath": "/var/lib/docker/containers/be5e4f7e3b6095df3f31688bbafb01b1451b525d8dcac00caab8118f6fe79e49/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/be5e4f7e3b6095df3f31688bbafb01b1451b525d8dcac00caab8118f6fe79e49/hostname",
"HostsPath": "/var/lib/docker/containers/be5e4f7e3b6095df3f31688bbafb01b1451b525d8dcac00caab8118f6fe79e49/hosts",
"LogPath": "/var/lib/docker/containers/be5e4f7e3b6095df3f31688bbafb01b1451b525d8dcac00caab8118f6fe79e49/be5e4f7e3b6095df3f31688bbafb01b1451b525d8dcac00caab8118f6fe79e49-json.log",
"Name": "/sad_thompson",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "docker-default",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "shareable",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DiskQuota": 0,
"KernelMemory": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": 0,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/asound",
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/781a64920982797527c5ef86551a61624250b3f649af661c1cd618cb9825831c-init/diff:/var/lib/docker/overlay2/ae811b90ee67d993b294fb855c64eba3b2469fa7f0fb6d2295783a397585cc27/diff:/var/lib/docker/overlay2/7ebf1e23acd4760d0a5153e1c8cb22c08ebdb02963edfe9e69de7dbde0afb6f0/diff:/var/lib/docker/overlay2/f35346319e20df6c3a90d5addbec816c14926d824d79abf3ac43735efd445d3b/diff:/var/lib/docker/overlay2/89670666280bfa08f408324049fff595a15982e631a7225a6f9893e59eca5e25/diff:/var/lib/docker/overlay2/ac115e670adecb3ce0128b5b42080df10c3171c521e6c89dd57ea01edbea7135/diff:/var/lib/docker/overlay2/dd51071366ed977cd8a7e106bcaa2f0fccd4f2db40bd16336b15344784d8a1bc/diff:/var/lib/docker/overlay2/d00842c4e9442027f1d0775db01b6da00e54e61c8f10dd9d865425c10332cf85/diff:/var/lib/docker/overlay2/c8eb5b6d7edf558c467025cc38eecaa256e36fc717e4467760fd1b9e54fe2511/diff:/var/lib/docker/overlay2/b8293e1fb5da2f2cb1045e9c0e093fc7f2e22d9968186303f831a68c8db4fc4c/diff:/var/lib/docker/overlay2/ba40cff13392127849d0b5f9f441970f728d6a6d85718cd7a2bca803bd1b4bc0/diff:/var/lib/docker/overlay2/8b1d75385c1aaa42655be78a1bc7d722cc2b0be8786d84fd3c8219a08ec98564/diff:/var/lib/docker/overlay2/1244555d111c96e8c7f620936b12232794f7a855d38bbfbe9fdd2b8f63a6dc96/diff:/var/lib/docker/overlay2/db7479804960c2bdfbdbb29eeda1e2971c2697167c2db584570ec4f9f53396b6/diff",
"MergedDir": "/var/lib/docker/overlay2/781a64920982797527c5ef86551a61624250b3f649af661c1cd618cb9825831c/merged",
"UpperDir": "/var/lib/docker/overlay2/781a64920982797527c5ef86551a61624250b3f649af661c1cd618cb9825831c/diff",
"WorkDir": "/var/lib/docker/overlay2/781a64920982797527c5ef86551a61624250b3f649af661c1cd618cb9825831c/work"
},
"Name": "overlay2"
},
"Mounts": [
{
"Type": "volume",
"Name": "5df1d894fd851a5d1530e8f4732e440d85e27e3a4f758a523ffe1c94c93f1ecb",
"Source": "/var/lib/docker/volumes/5df1d894fd851a5d1530e8f4732e440d85e27e3a4f758a523ffe1c94c93f1ecb/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
"Config": {
"Hostname": "be5e4f7e3b60",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"3306/tcp": {},
"33060/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"GOSU_VERSION=1.12",
"MYSQL_MAJOR=8.0",
"MYSQL_VERSION=8.0.19-1debian10",
"MYSQL_ROOT_PASSWORD=6666",
"MYSQL_ALLOW_EMPTY_PASSWORD=no",
"MYSQL_DATABASE=docker_mysql",
"MYSQL_USER=docker",
"MYSQL_PASSWORD=123456"
],
"Cmd": [
"mysqld"
],
"ArgsEscaped": true,
"Image": "mysql:lxc",
"Volumes": {
"/var/lib/mysql": {}
},
"WorkingDir": "",
"Entrypoint": [
"docker-entrypoint.sh"
],
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "31cb57d7c658e5f48aa105e511c6afda30166925445d9ff4c7d66fcc456b4540",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"3306/tcp": null,
"33060/tcp": null
},
"SandboxKey": "/var/run/docker/netns/31cb57d7c658",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "66b523529f6f550223d4bcefc390c7979dd2bb931205ec699e47ce226c03c798",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:03",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "c2e54a3661207b2e741d5f9566ee9363a8b4902540e2eb56c3b79b6f53993ac0",
"EndpointID": "66b523529f6f550223d4bcefc390c7979dd2bb931205ec699e47ce226c03c798",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:03",
"DriverOpts": null
}
}
}
}
]
(ps:若要查询部分信息,请参考查看docker容器的信息)
至此,利用dockerfile成功搭建自定义mysql数据库容器服务。
👉三.小结
这次的实验其实并不难,但过程中还是遇到了不少小麻烦,反正是大坑没有,小坑一堆。在这里总结一下自己踩过的坑和遇到的问题:
- 关于dockerfile中EXPOSE的误解
一开始我对EXPOSE的理解是:只要在dockerfile中写上EXPOSE 端口号
就能够在运行的时候通过这个端口监听容器,上网查阅的资料中也都可以直接在运行的时候进行主机端口和容器端口的映射,但是到了自己试验的时候却发现无法使用通过主机映射expose的端口号访问容器(给👴整😲了)。之后不停查阅资料试都没能解决,后来实在百思不得其解,咨询了老师。经老师一语点拨,我大彻大悟,原来EXPOSE 端口号
只是声明,要使用这个端口号还得再配置文件中添加上监听要暴露的端口号的内容(我哭了😩😩)。由于对httpd不了解,编写配置文件也变得格外困难,最后还是通过老师的指点才找到了上述编写httpd配置文件的方法,总算是解决了这个问题。
- 发现了mysql镜像的一些问题
对于最新版的mysql镜像,无法使用service mysql start|stop
来对容器的mysql进行控制(会报错:unrecognized service),导致一些脚本文件在容器运行时无法正常执行。
对于5.7版本的mysql镜像,使用dockerfile构建mysql并初始化数据执行脚本文件后,会使得不管你是否设置了root账户能否免密登录,在运行的时候root账户都可以免密登录,而且在用root账户密码登录时,输入任何密码都能登录,能力有限,无法查明这个问题出自什么原因。如有大佬知晓其因,还望大佬不惜浪费一点时间,为鄙人指点迷津🙏🙏!
虽然实验过程有很多小插曲,但庆幸自己没有自暴自弃,还是坚持了下来,完成了实验。希望自己再接再厉,在接下来的实验中学到更多奇怪的知识!😁😁