到目前为止大家应该对镜像和容器有了一个大概认知, 而且也用了 docker 进行了一个简单化的部署, 但仔细一看问题还有很多, 所以这篇我们继续完善.
一: 如何让外网访问到容器内应用
我们知道容器内拥有自己的子网, 和你的主机 ip 不在一个网段内, 所以宿主之外的机器是无法访问的, 要实现的话你只能通过 nat 转发, 在 docker 上实现起
来很简单, 通过 -p 将容器端口映射到宿主机端口即可.
1. 在 Dockerfile 中, 容器会自动监听 8080 端口, 而且我的程序也是开启了这个端口号.
- FROM microsoft/dotnet:2.2-aspnetcore-runtime
- LABEL author hxc@qq.com
- RUN mkdir /data
- COPY ./ /data
- WORKDIR /data
- VOLUME /data/log
- EXPOSE 8080
- CMD [ "dotnet","webNotebook.dll" ]
- public class Program
- {
- public static void Main(string[] args)
- {
- CreateWebHostBuilder(args).Build().Run();
- }
- public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
- WebHost.CreateDefaultBuilder(args)
- .UseUrls("http://*:8080")
- .UseStartup<Startup>();
- }
2. 接下来通过 -p 端口映射, 将宿主机的 8080 端口和容器的 8080 端口进行一个映射, 前面是宿主机端口, 后面是容器的, 你也可以写成 hostip:8080:8080
- [root@localhost ~]# docker run -d --name webnotebook -p 8080:8080 huangxincheng520/webnotebook:v4
- 82cf45e8fb7281fda7d1b22bf6ef1a5156a75f04b4ef29873d44f161b0238cfb
- [root@localhost ~]#
- [root@localhost ~]# docker ps
- CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- 82cf45e8fb72 huangxincheng520/webnotebook:v4 "dotnet WebNotebook...." 3 seconds ago Up 2 seconds 0.0.0.0:8080->8080/tcp webnotebook
3. 然后我就可以在 Windows 上输入网址访问了, 可以看到一点问题都没有.
4. 有些人可能会很好奇的去问, 这个是怎么做到的呢? 刚才也说到了是通过 nat 进行协议头 ip 地址替换进行转发的, 你要是不信的话, 可以用 CentOS 的
iptables nat 去查看一下.
- [root@localhost ~]# iptables -t nat -L -n
- Chain PREROUTING (policy ACCEPT)
- target prot opt source destination
- DOCKER all -- 0.0.0.0/0 0.0.0.0/0 ADDRTYPE match dst-type LOCAL
- Chain INPUT (policy ACCEPT)
- target prot opt source destination
- Chain OUTPUT (policy ACCEPT)
- target prot opt source destination
- DOCKER all -- 0.0.0.0/0 !127.0.0.0/8 ADDRTYPE match dst-type LOCAL
- Chain POSTROUTING (policy ACCEPT)
- target prot opt source destination
- MASQUERADE all -- 172.17.0.0/16 0.0.0.0/0
- RETURN all -- 192.168.122.0/24 224.0.0.0/24
- RETURN all -- 192.168.122.0/24 255.255.255.255
- MASQUERADE tcp -- 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535
- MASQUERADE udp -- 192.168.122.0/24 !192.168.122.0/24 masq ports: 1024-65535
- MASQUERADE all -- 192.168.122.0/24 !192.168.122.0/24
- MASQUERADE tcp -- 172.17.0.2 172.17.0.2 tcp dpt:8080
- Chain DOCKER (2 references)
- target prot opt source destination
- RETURN all -- 0.0.0.0/0 0.0.0.0/0
- DNAT tcp -- 0.0.0.0/0 0.0.0.0/0 tcp dpt:8080 to:172.17.0.2:8080
可以看到, docker 在 iptables 中实现了一个自己的 Docker chain, 从 hostIP:8080 -> 172.17.0.2:8080 中可以看到, 当一个请求到了 192.168.23.149:8080
会自动转发到 172.17.0.2.8080, 有些人可能会问, 这个明显不是一个网段怎么转发呢? 那是因为你的宿主机上有一个默认的网桥 Docker0, 你可以理解成
他就是一个数据链路层上的路由器, 通过这个路由器, 可以将不同的网段进行互联, 你可以用 ipconfig 查看 docker0 的 ip 地址, 这个 ip 地址就相当于路由器 ip,
也即是子网地址.
- [root@localhost ~]# ifconfig
- docker0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
- .NET 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
- inet6 fe80::42:25ff:fe14:8a13 prefixlen 64 scopeid 0x20<link>
- ether 02:42:25:14:8a:13 txqueuelen 0 (Ethernet)
- RX packets 105061 bytes 8399597 (8.0 MiB)
- RX errors 0 dropped 0 overruns 0 frame 0
- TX packets 148379 bytes 425576796 (405.8 MiB)
- TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
- ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
- .NET 192.168.23.149 netmask 255.255.255.0 broadcast 192.168.23.255
- inet6 fe80::20c:29ff:fe5c:2e32 prefixlen 64 scopeid 0x20<link>
- ether 00:0c:29:5c:2e:32 txqueuelen 1000 (Ethernet)
- RX packets 1570930 bytes 2222888854 (2.0 GiB)
- RX errors 0 dropped 0 overruns 0 frame 0
- TX packets 532628 bytes 56478232 (53.8 MiB)
- TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
- lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
- .NET 127.0.0.1 netmask 255.0.0.0
- inet6 ::1 prefixlen 128 scopeid 0x10<host>
- loop txqueuelen 0 (Local Loopback)
- RX packets 104 bytes 8816 (8.6 KiB)
- RX errors 0 dropped 0 overruns 0 frame 0
- TX packets 104 bytes 8816 (8.6 KiB)
- TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
- veth871156e: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
- inet6 fe80::3c7f:5fff:fe53:4542 prefixlen 64 scopeid 0x20<link>
- ether 3e:7f:5f:53:45:42 txqueuelen 0 (Ethernet)
- RX packets 99 bytes 726984 (709.9 KiB)
- RX errors 0 dropped 0 overruns 0 frame 0
- TX packets 306 bytes 19235 (18.7 KiB)
- TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
- virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
- .NET 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
- ether 52:54:00:83:96:c2 txqueuelen 0 (Ethernet)
- RX packets 0 bytes 0 (0.0 B)
- RX errors 0 dropped 0 overruns 0 frame 0
- TX packets 0 bytes 0 (0.0 B)
- TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
二: 如何处理容器中的日志数据
我们的 webnotebook 运行的时候总会产生一些日志, 这时候可以把日志文件夹挂载到宿主机上, 方便查看和采集啥的, 当然更多的情况是采用集中式
的日志收集, 这个就不是本篇所讨论的了, 接下来我要做两件事情, 配置 nlog 日志框架, 然后进行 docker 目录挂载.
1. 配置 nlog 框架, 在 nuget 上下载
2. nlog.config 配置如下,{basedir} 就是当前程序的根目录.
- <?xml version="1.0" encoding="utf-8" ?>
- <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <targets>
- <target name="file_info" xsi:type="File"
- fileName="${basedir}/log/${shortdate}.txt" maxArchiveFiles="30"
- layout="${longdate} | ${level:uppercase=false} | ${message} ${onexception:${exception:format=tostring} ${newline} ${stacktrace} ${newline}" />
- </targets>
- <rules>
- <logger name="*" writeTo="file_info" />
- </rules>
- </nlog>
3. 然后我们的 Controller 类修改一下, 记录下客户端的 ip 地址.
- public class HomeController : Controller
- {
- public static Logger logger = LogManager.GetLogger("SimpleDemo");
- /// <summary>
- /// 读取 MongoDB 数据数据
- /// </summary>
- /// <returns></returns>
- public IActionResult Index()
- {
- var log = $"客户端:{HttpContext.Connection.RemoteIpAddress} 访问了 Index 页面!";
- logger.Info(log);
- return View();
- }
- }
4. 接下来你就可以 docker build 成镜像啦, 在 docker run 中使用 - v 参数, 将宿主机的 /data/log 挂载到容器的 /data/log 目录, 如下命令.
- [root@localhost publish]# docker build -t huangxincheng520/webnotebook:v5 -f ./Dockerfile .
- [root@localhost publish]# docker run --name webnotebook5 -d -p 8080:8080 -v /data/log:/data/log huangxincheng520/webnotebook:v5
- 0e03f54d69ccdf3f88511385fd6fd5fdcafb64c0f971cbadb0b93014cb79e375
5. 一切都部署好了, 接下来你可以访问 8080 端口, 然后到你的宿主机的 / data/log 目录下查看一下, 你的日志就出来啦.
- [root@localhost log]# pwd
- /data/log
- [root@localhost log]# ls
- 2019-02-20.txt
- [root@localhost log]# tail 2019-02-20.txt
2019-02-20 04:13:36.2904 | Info | 客户端:::ffff:192.168.23.1 访问了 Index 页面!
[root@localhost log]#
细心的你应该会发现到, 日志所打印出的时间出了问题, 比北京时间少了 8 个小时, 所以你要做的是, 把默认的 0 区时间改成东 8 区即可, 那怎么修改呢?
《1》 在 docker run 中加入 -e 参数, 也就是加入环境变量 -e TZ=Asia/Shanghai 即可, 不要怕参数多, 以后这些都是通过 CI 工具集成的, 不要怕哈.
- [root@localhost publish]# docker run --name webnotebook5 -d -p 8080:8080 -v /data/log:/data/log -e TZ=Asia/Shanghai huangxincheng520/webnotebook:v5
- 18cbd284dbd6f6ff498d849eda7652ec63df3c0113c0cdd53ae4a0030abb52f2
访问网站之后再看看你的 log 文件, 时区已经调整过来了.
[root@localhost log]# tail 2019-02-20.txt
2019-02-20 04:13:36.2904 | Info | 客户端:::ffff:192.168.23.1 访问了 Index 页面!
2019-02-20 12:20:38.3752 | Info | 客户端:::ffff:192.168.23.1 访问了 Index 页面!
《2》 在 dockerfile 中增加环境变量占位符.
- FROM microsoft/dotnet:2.2-aspnetcore-runtime
- ENV TZ Asia/Shanghai
好了, 本篇就说到这里, 希望对你有帮助.
来源: https://www.cnblogs.com/huangxincheng/p/10405856.html