页面缓存、内存和文件之间的那些事
Media上一篇文章中我们学习了内核怎么为一个用户进程 管理虚拟内存,而没有提及文件和 I/O。这一篇文章我们将专门去讲这个重要的主题 —— 页面缓存。文件和内存之间的关系常常很不好去理解,而它们对系统性能的影响却是非常大的。在面对文件时,有两个很重要的问题需要操作系统去解决。第一个是相对内存而言,慢的让人发狂的硬盘驱动器,尤其是磁盘寻道。第二个是需要将文件内容一次性地加载到物理内存中,以便程序间共享文件内容。如果你在 Windows 中使用 进程浏览器 去查看它的进程,你将会看到每个进程中加载了大约 ~15MB 的公共 DLL。我的 Windows 机器上现在大约运行着 100 个进程,因此,如果不共享的话,仅这些公共的 DLL 就要使用高达 ~1.5 GB 的物理内存。如果是那样的话,那就太糟糕了。同样的,几乎所有的 Linux 进程都需要 ld.so 和 libc,加上其它的公共库,它们占用的内存数量也不是一个小数目。幸运的是,这两个问题都用一个办法解决了:页面缓存 —— 保存在内存中的页面大小的文件块。为了用图去说明页面缓存,我捏造出一个名为
via https://linux.cn/article-9528-1.html?utm_source=rss&utm_medium=rss
Media上一篇文章中我们学习了内核怎么为一个用户进程 管理虚拟内存,而没有提及文件和 I/O。这一篇文章我们将专门去讲这个重要的主题 —— 页面缓存。文件和内存之间的关系常常很不好去理解,而它们对系统性能的影响却是非常大的。在面对文件时,有两个很重要的问题需要操作系统去解决。第一个是相对内存而言,慢的让人发狂的硬盘驱动器,尤其是磁盘寻道。第二个是需要将文件内容一次性地加载到物理内存中,以便程序间共享文件内容。如果你在 Windows 中使用 进程浏览器 去查看它的进程,你将会看到每个进程中加载了大约 ~15MB 的公共 DLL。我的 Windows 机器上现在大约运行着 100 个进程,因此,如果不共享的话,仅这些公共的 DLL 就要使用高达 ~1.5 GB 的物理内存。如果是那样的话,那就太糟糕了。同样的,几乎所有的 Linux 进程都需要 ld.so 和 libc,加上其它的公共库,它们占用的内存数量也不是一个小数目。幸运的是,这两个问题都用一个办法解决了:页面缓存 —— 保存在内存中的页面大小的文件块。为了用图去说明页面缓存,我捏造出一个名为
render 的 Linux 程序,它打开了文件 scene.dat,并且一次读取 512 字节,并将文件内容存储到一个分配到堆中的块上。第一次读取的过程如下:Reading and the page cacherender 请求 scene.dat 从位移 0 开始的 512 字节。内核搜寻页面缓存中 scene.dat 的 4kb 块,以满足该请求。假设该数据没有缓存。内核分配页面帧,初始化 I/O 请求,将 scend.dat 从位移 0 开始的 4kb 复制到分配的页面帧。内核从页面缓存复制请求的 512 字节到用户缓冲区,系统调用 read() 结束。读取完 12KB 的文件内容以后,render 程序的堆和相关的页面帧如下图所示:Non-mapped file read它看起来很简单,其实这一过程做了很多的事情。首先,虽然这个程序使用了普通的读取(read)调用,但是,已经有三个 4KB 的页面帧将文件 scene.dat 的一部分内容保存在了页面缓存中。虽然有时让人觉得很惊奇,但是,普通的文件 I/O 就是这样通过页面缓存来进行的。在 x86 架构的 Linux 中,内核将文件认为是一系列的 4KB 大小的块。如果你从文件中读取单个字节,包含这个字节的整个 4KB 块将被从磁盘中读入到页面缓存中。这是可以理解的,因为磁盘通常是持续吞吐的,并且程序一般也不会从磁盘区域仅仅读取几个字节。页面缓存知道文件中的每个 4KB 块的位置,在上图中用 #0、#1 等等来描述。Windows 使用 256KB 大小的视图view,类似于 Linux 的页面缓存中的页面page。不幸的是,在一个普通的文件读取中,内核必须拷贝页面缓存中的内容到用户缓冲区中,它不仅花费 CPU 时间和影响 CPU 缓存,在复制数据时也浪费物理内存。如前面的图示,scene.dat 的内存被存储了两次,并且,程序中的每个实例都用另外的时间去存储内容。我们虽然解决了从磁盘中读取文件缓慢的问题,但是在其它的方面带来了更痛苦的问题。内存映射文件是解决这种痛苦的一个方法:Mapped file read当你使用文件映射时,内核直接在页面缓存上映射你的程序的虚拟页面。这样可以显著提升性能:Windows 系统编程 报告指出,在相关的普通文件读取上运行时性能提升多达 30% ,在 Unix 环境中的高级编程 的报告中,文件映射在 Linux 和 Solaris 也有类似的效果。这取决于你的应用程序类型的不同,通过使用文件映射,可以节约大量的物理内存。对高性能的追求是永恒不变的目标,测量是很重要的事情,内存映射应该是程序员始终要使用的工具。这个 API 提供了非常好用的实现方式,它允许你在内存中按字节去访问一个文件,而不需要为了这种好处而牺牲代码可读性。在一个类 Unix 的系统中,可以使用 mmap 查看你的 地址空间,在 Windows 中,可以使用 CreateFileMapping,或者在高级编程语言中还有更多的可用封装。当你映射一个文件内容时,它并不是一次性将全部内容都映射到内存中,而是通过 页面故障 来按需映射的。在 获取 需要的文件内容的页面帧后,页面故障句柄 映射你的虚拟页面 到页面缓存上。如果一开始文件内容没有缓存,这还将涉及到磁盘 I/O。现在出现一个突发的状况,假设我们的 render 程序的最后一个实例退出了。在页面缓存中保存着 scene.dat 内容的页面要立刻释放掉吗?人们通常会如此考虑,但是,那样做并不是个好主意。你应该想到,我们经常在一个程序中创建一个文件,退出程序,然后,在第二个程序去使用这个文件。页面缓存正好可以处理这种情况。如果考虑更多的情况,内核为什么要清除页面缓存的内容?请记住,磁盘读取的速度要慢于内存 5 个数量级,因此,命中一个页面缓存是一件有非常大收益的事情。因此,只要有足够大的物理内存,缓存就应该保持全满。并且,这一原则适用于所有的进程。如果你现在运行 render 一周后, scene.dat 的内容还在缓存中,那么应该恭喜你!这就是什么内核缓存越来越大,直至达到最大限制的原因。它并不是因为操作系统设计的太“垃圾”而浪费你的内存,其实这是一个非常好的行为,因为,释放物理内存才是一种“浪费”。(LCTT 译注:释放物理内存会导致页面缓存被清除,下次运行程序需要的相关数据,需要再次从磁盘上进行读取,会“浪费” CPU 和 I/O 资源)最好的做法是尽可能多的使用缓存。由于页面缓存架构的原因,当程序调用 write() 时,字节只是被简单地拷贝到页面缓存中,并将这个页面标记为“脏”页面。磁盘 I/O 通常并不会立即发生,因此,你的程序并不会被阻塞在等待磁盘写入上。副作用是,如果这时候发生了电脑死机,你的写入将不会完成,因此,对于至关重要的文件,像数据库事务日志,要求必须进行 fsync()(仍然还需要去担心磁盘控制器的缓存失败问题),另一方面,读取将被你的程序阻塞,直到数据可用为止。内核采取预加载的方式来缓解这个矛盾,它一般提前预读取几个页面并将它加载到页面缓存中,以备你后来的读取。在你计划进行一个顺序或者随机读取时(请查看 madvise()、readahead()、Windows 缓存提示 ),你可以通过提示hint帮助内核去调整这个预加载行为。Linux 会对内存映射的文件进行 预读取,但是我不确定 Windows 的行为。当然,在 Linux 中它可能会使用 O_DIRECT 跳过预读取,或者,在 Windows 中使用 NO_BUFFERING 去跳过预读,一些数据库软件就经常这么做。一个文件映射可以是私有的,也可以是共享的。当然,这只是针对内存中内容的更新而言:在一个私有的内存映射上,更新并不会提交到磁盘或者被其它进程可见,然而,共享的内存映射,则正好相反,它的任何更新都会提交到磁盘上,并且对其它的进程可见。内核使用写时复制copy on write(CoW)机制,这是通过页面表条目page table entry(PTE)来实现这种私有的映射。在下面的例子中,render 和另一个被称为 render3d 的程序都私有映射到 scene.dat 上。然后 render 去写入映射的文件的虚拟内存区域:The Copy-On-Write mechanism两个程序私有地映射 scene.dat,内核误导它们并将它们映射到页面缓存,但是使该页面表条目只读。render 试图写入到映射 scene.dat 的虚拟页面,处理器发生页面故障。内核分配页面帧,复制 scene.dat 的第二块内容到其中,并映射故障的页面到新的页面帧。继续执行。程序就当做什么都没发生。上面展示的只读页面表条目并不意味着映射是只读的,它只是内核的一个用于共享物理内存的技巧,直到尽可能的最后一刻之前。你可以认为“私有”一词用的有点不太恰当,你只需要记住,这个“私有”仅用于更新的情况。这种设计的重要性在于,要想看到被映射的文件的变化,其它程序只能读取它的虚拟页面。一旦“写时复制”发生,从其它地方是看不到这种变化的。但是,内核并不能保证这种行为,因为它是在 x86 中实现的,从 API 的角度来看,这是有意义的。相比之下,一个共享的映射只是将它简单地映射到页面缓存上。更新会被所有的进程看到并被写入到磁盘上。最终,如果上面的映射是只读的,页面故障将触发一个内存段失败而不是写到一个副本。动态加载库是通过文件映射融入到你的程序的地址空间中的。这没有什么可奇怪的,它通过普通的 API 为你提供与私有文件映射相同的效果。下面的示例展示了映射文件的 render 程序的两个实例运行的地址空间的一部分,以及物理内存,尝试将我们看到的许多概念综合到一起。Mapping virtual memory to physical memory这是内存架构系列的第三部分的结论。我希望这个系列文章对你有帮助,对理解操作系统的这些主题提供一个很好的思维模型。via:https://manybutfinite.com/post/page-cache-the-affair-between-memory-and-files/作者:Gustavo Duarte 译者:qhwdw 校对:wxy本文由 LCTT 原创编译,Linux中国 荣誉推出Mediavia https://linux.cn/article-9528-1.html?utm_source=rss&utm_medium=rss
让我们做个简单的解释器(三)
识别出记号流中的词组的过程就叫做 解析。解释器或者编译器执行这个任务的部分叫做 解析器。解析也称为 语法分析,并且解析器这个名字很合适,你猜的对,就是 语法分析器。Media
via https://linux.cn/article-9521-1.html
识别出记号流中的词组的过程就叫做 解析。解释器或者编译器执行这个任务的部分叫做 解析器。解析也称为 语法分析,并且解析器这个名字很合适,你猜的对,就是 语法分析器。Media
via https://linux.cn/article-9521-1.html
如何解决 “mount.nfs: Stale file handle”错误
了解如何解决 Linux 平台上的 mount.nfs: Stale file handle 错误。这个 NFS 错误可以在客户端或者服务端解决。Media
via https://linux.cn/article-9530-1.html
了解如何解决 Linux 平台上的 mount.nfs: Stale file handle 错误。这个 NFS 错误可以在客户端或者服务端解决。Media
via https://linux.cn/article-9530-1.html
如何解决 “mount.nfs: Stale file handle”错误
了解如何解决 Linux 平台上的 mount.nfs: Stale file handle 错误。这个 NFS 错误可以在客户端或者服务端解决。Media当你在你的环境中使用网络文件系统时,你一定不时看到 mount.nfs:Stale file handle 错误。此错误表示 NFS 共享无法挂载,因为自上次配置后有些东西已经更改。无论是你重启 NFS 服务器或某些 NFS 进程未在客户端或服务器上运行,或者共享未在服务器上正确输出,这些都可能是导致这个错误的原因。此外,当这个错误发生在先前挂载的 NFS 共享上时,它会令人不快。因为这意味着配置部分是正确的,因为是以前挂载的。在这种情况下,可以尝试下面的命令:确保 NFS 服务在客户端和服务器上运行良好。
via https://linux.cn/article-9530-1.html?utm_source=rss&utm_medium=rss
了解如何解决 Linux 平台上的 mount.nfs: Stale file handle 错误。这个 NFS 错误可以在客户端或者服务端解决。Media当你在你的环境中使用网络文件系统时,你一定不时看到 mount.nfs:Stale file handle 错误。此错误表示 NFS 共享无法挂载,因为自上次配置后有些东西已经更改。无论是你重启 NFS 服务器或某些 NFS 进程未在客户端或服务器上运行,或者共享未在服务器上正确输出,这些都可能是导致这个错误的原因。此外,当这个错误发生在先前挂载的 NFS 共享上时,它会令人不快。因为这意味着配置部分是正确的,因为是以前挂载的。在这种情况下,可以尝试下面的命令:确保 NFS 服务在客户端和服务器上运行良好。
# service nfs statusrpc.svcgssd is stoppedrpc.mountd (pid 11993) is running...nfsd (pid 12009 12008 12007 12006 12005 12004 12003 12002) is running...rpc.rquotad (pid 11988) is running...如果 NFS 共享目前挂载在客户端上,则强制卸载它并尝试在 NFS 客户端上重新挂载它。通过 df 命令检查它是否正确挂载,并更改其中的目录。
# umount -f /mydata_nfs# mount -t nfs server:/nfs_share /mydata_nfs#df -k------ output clipped -----server:/nfs_share 41943040 892928 41050112 3% /mydata_nfs在上面的挂载命令中,服务器可以是 NFS 服务器的 IP 或主机名。如果你在强制取消挂载时遇到像下面错误:
# umount -f /mydata_nfsumount2: Device or resource busyumount: /mydata_nfs: device is busyumount2: Device or resource busyumount: /mydata_nfs: device is busy然后你可以用 lsof 命令来检查哪个进程或用户正在使用该挂载点,如下所示:
# lsof |grep mydata_nfslsof: WARNING: can't stat() nfs file system /mydata_nfs Output information may be incomplete.su 3327 root cwd unknown /mydata_nfs/dir (stat: Stale NFS file handle)bash 3484 grid cwd unknown /mydata_nfs/MYDB (stat: Stale NFS file handle)bash 20092 oracle11 cwd unknown /mydata_nfs/MPRP (stat: Stale NFS file handle)bash 25040 oracle11 cwd unknown /mydata_nfs/MUYR (stat: Stale NFS file handle)如果你在上面的示例中看到共有 4 个 PID 正在使用该挂载点上的某些文件。尝试杀死它们以释放挂载点。完成后,你将能够正确卸载它。有时 mount 命令会有相同的错误。接着使用下面的命令在客户端重启 NFS 服务后挂载。
# service nfs restartShutting down NFS daemon: [ OK ]Shutting down NFS mountd: [ OK ]Shutting down NFS quotas: [ OK ]Shutting down RPC idmapd: [ OK ]Starting NFS services: [ OK ]Starting NFS quotas: [ OK ]Starting NFS mountd: [ OK ]Starting NFS daemon: [ OK ]另请阅读:如何在 HPUX 中逐步重启 NFS即使这没有解决你的问题,最后一步是在 NFS 服务器上重启服务。警告!这将断开从该 NFS 服务器输出的所有 NFS 共享。所有客户端将看到挂载点断开。这一步将 99% 解决你的问题。如果没有,请务必检查 NFS 配置,提供你修改的配置并发布你启动时看到的错误。上面文章中的输出来自 RHEL6.3 服务器。请将你的评论发送给我们。via: https://kerneltalks.com/troubleshooting/resolve-mount-nfs-stale-file-handle-error/作者:KernelTalks 译者:geekpi 校对:wxy本文由 LCTT 原创编译,Linux中国 荣誉推出Media
via https://linux.cn/article-9530-1.html?utm_source=rss&utm_medium=rss
Linux 中的 5 个 SSH 别名例子
我们可以用 定义在你的 .bashrc 文件里的别名 或函数来大幅度缩减花在命令行界面(CLI)的时间。但这不是最佳解决之道。最佳办法是在 ssh 配置文件中使用 SSH 别名 。Media
via https://linux.cn/article-9531-1.html
我们可以用 定义在你的 .bashrc 文件里的别名 或函数来大幅度缩减花在命令行界面(CLI)的时间。但这不是最佳解决之道。最佳办法是在 ssh 配置文件中使用 SSH 别名 。Media
via https://linux.cn/article-9531-1.html
使用 Graylog 和 Prometheus 监视 Kubernetes 集群
在本文中,我将使用 Graylog (用于日志)和 Prometheus (用于指标)去打造一个 Kubernetes 集群的监视解决方案。Media
via https://linux.cn/article-9534-1.html
在本文中,我将使用 Graylog (用于日志)和 Prometheus (用于指标)去打造一个 Kubernetes 集群的监视解决方案。Media
via https://linux.cn/article-9534-1.html
UMStor Hadapter:大数据与对象存储的柳暗花明
HDFS 仍旧是“计算存储融合”阵营的定海神针,不过,我们也在 Hadapter 上看到了“计算存储分离”的新未来。Media
via https://linux.cn/article-9535-1.html
HDFS 仍旧是“计算存储融合”阵营的定海神针,不过,我们也在 Hadapter 上看到了“计算存储分离”的新未来。Media
via https://linux.cn/article-9535-1.html
怎样用 parted 管理硬盘分区
parted 是一个操作硬盘分区的程序。它支持多种分区表类型,包括 MS-DOS 和 GPT。Media
via https://linux.cn/article-9536-1.html
parted 是一个操作硬盘分区的程序。它支持多种分区表类型,包括 MS-DOS 和 GPT。Media
via https://linux.cn/article-9536-1.html
深度学习战争:Facebook 支持的 PyTorch 与 Google 的 TensorFlow
在这篇文章中,我们将 PyTorch 与 TensorFlow 进行不同方面的比较。Media
via https://linux.cn/article-9533-1.html
在这篇文章中,我们将 PyTorch 与 TensorFlow 进行不同方面的比较。Media
via https://linux.cn/article-9533-1.html
高级 SSH 速查表
Media所有人都知道 SSH 是一种远程登录工具,然而它也有许多其他用途。创建一个 SOCKS 代理来浏览网页(也就是翻墙啦):
-6 (仅使用 IPv6)AddressFamily <any,inet4,inet6>指定仅使用 IPv4 或者 IPv6。-L <local port>:<target host>:<target port>LocalForward <local port>:<target host>:<target port>把本地主机指定端口的报文转发到远程主机的某个端口。opensource.com Twitter @opensourceway | facebook.com/opensourceway | IRC: #opensource.com on Freenode作者简介:Ben Cotton 是业余的气象学家和职业的高性能计算工程师。Ben 是微软 Azure 的产品营销经理,专注于高性能计算。他是一个 Fedora 用户和贡献者,共同创立了一个当地的开放源码群,并且是开源促进会的成员和保护自由软件的支持者。通过以下方式联系他 Twitter (@FunnelFiasco) 或者 FunnelFiasco.com.via: https://opensource.com/sites/default/files/gated-content/cheat_sheet_ssh_v03.pdf作者:BEN COTTON 译者:kennethXia 校对:wxy本文由 LCTT 原创编译,Linux中国 荣誉推出Media
via https://linux.cn/article-9540-1.html?utm_source=rss&utm_medium=rss
Media所有人都知道 SSH 是一种远程登录工具,然而它也有许多其他用途。创建一个 SOCKS 代理来浏览网页(也就是翻墙啦):
ssh -D <port> <remote_host>设置 localhost:<port> 作为你浏览器的代理连接一个堡垒机后的 Windows RDP 主机:
ssh -L <port>:<target_host>:3389 <bastion_server>让你的 RDP 客户端连接到 localhost:<port>在不使用 VNC 端口的情况下,连接远程 VNC 主机:
ssh -L 5901:localhost:5901 <remote_host>让你的 VNC 客户端连接到 localhost:5901按照这个思路,你可以映射任意端口:LDAP (389)、631 (CUPS)、8080 (替代的 HTTP),等等。产生一个新的 SSH 密钥对:
ssh-keygen更新密钥对的密码:
ssh-keygen -p把公钥复制到远程主机上:
ssh-copy-id -i <identity file> <remote_host>SSH 有一堆命令行选项,但是如果有一些是你经常使用的,你可以为它们在 SSH 配置文件 (${HOME}/.ssh/config) 里创建一个入口。比如:
host myhouse User itsme HostName house.example.com那么你就可以输入 ssh myhouse 来代替 ssh itsme@house.example.com。以下是常用的命令行选项和他们的配置文件写法。一些是常用的简化写法。请查看 ssh(1) 和 ssh_config(5) 的手册页来获取详尽信息。命令行配置文件描述-l <login name>User <login name>远程主机的登录用户名。-i <identity file>IdentityFile <identity file>指定要使用的鉴权文件(SSH 密码对)。-p <remote port>Port <remote port>远程 SSH 守护进程监听的端口号。 (默认为 22)-CCompression <yes,no>压缩往来信息。 (默认为 no)-D <port>DynamicForward <port>把本地端口的报文转发到远程主机。-XForwardX11 <yes,no>把 X11 的图像数据转发到远程主机的端口. (默认为 no)-AForwardAgent <yes,no>把授权代理的报文转发给远程主机。如果你使用第三方主机登录,这个功能将很有用。 (默认为 no)-4(仅使用 IPv4)
-6 (仅使用 IPv6)AddressFamily <any,inet4,inet6>指定仅使用 IPv4 或者 IPv6。-L <local port>:<target host>:<target port>LocalForward <local port>:<target host>:<target port>把本地主机指定端口的报文转发到远程主机的某个端口。opensource.com Twitter @opensourceway | facebook.com/opensourceway | IRC: #opensource.com on Freenode作者简介:Ben Cotton 是业余的气象学家和职业的高性能计算工程师。Ben 是微软 Azure 的产品营销经理,专注于高性能计算。他是一个 Fedora 用户和贡献者,共同创立了一个当地的开放源码群,并且是开源促进会的成员和保护自由软件的支持者。通过以下方式联系他 Twitter (@FunnelFiasco) 或者 FunnelFiasco.com.via: https://opensource.com/sites/default/files/gated-content/cheat_sheet_ssh_v03.pdf作者:BEN COTTON 译者:kennethXia 校对:wxy本文由 LCTT 原创编译,Linux中国 荣誉推出Media
via https://linux.cn/article-9540-1.html?utm_source=rss&utm_medium=rss
如何创建一个 Docker 镜像
Media在 前面的文章 中,我们学习了在 Linux、macOS、以及 Windows 上如何使用 Docker 的基础知识。在这篇文章中,我们将学习创建 Docker 镜像的基本知识。我们可以在 DockerHub 上得到可用于你自己的项目的预构建镜像,并且也可以将你自己的镜像发布到这里。我们使用预构建镜像得到一个基本的 Linux 子系统,因为,从头开始构建需要大量的工作。你可以使用 Alpine( Docker 版使用的官方版本)、Ubuntu、BusyBox、或者 scratch。在我们的示例中,我将使用 Ubuntu。在我们开始构建镜像之前,让我们先“容器化”它们!我的意思是,为你的所有 Docker 镜像创建目录,这样你就可以维护不同的项目和阶段,并保持它们彼此隔离。
via https://linux.cn/article-9541-1.html?utm_source=rss&utm_medium=rss
Media在 前面的文章 中,我们学习了在 Linux、macOS、以及 Windows 上如何使用 Docker 的基础知识。在这篇文章中,我们将学习创建 Docker 镜像的基本知识。我们可以在 DockerHub 上得到可用于你自己的项目的预构建镜像,并且也可以将你自己的镜像发布到这里。我们使用预构建镜像得到一个基本的 Linux 子系统,因为,从头开始构建需要大量的工作。你可以使用 Alpine( Docker 版使用的官方版本)、Ubuntu、BusyBox、或者 scratch。在我们的示例中,我将使用 Ubuntu。在我们开始构建镜像之前,让我们先“容器化”它们!我的意思是,为你的所有 Docker 镜像创建目录,这样你就可以维护不同的项目和阶段,并保持它们彼此隔离。
$ mkdir dockerprojectscd dockerprojects现在,在 dockerprojects 目录中,你可以使用自己喜欢的文本编辑器去创建一个 Dockerfile 文件;我喜欢使用 nano,它对新手来说很容易上手。
$ nano Dockerfile然后添加这样的一行内容:
FROM UbuntuMedia使用 Ctrl+Exit 然后选择 Y 去保存它。现在开始创建你的新镜像,然后给它起一个名字(在刚才的目录中运行如下的命令):
$ docker build -t dockp .(注意命令后面的圆点)这样就创建成功了,因此,你将看到如下内容:
Sending build context to Docker daemon 2.048kBStep 1/1 : FROM ubuntu---> 2a4cca5ac898Successfully built 2a4cca5ac898Successfully tagged dockp:latest现在去运行和测试一下你的镜像:
$ docker run -it Ubuntu你将看到 root 提示符:
root@c06fcd6af0e8:/#这意味着在 Linux、Windows、或者 macOS 中你可以运行一个最小的 Ubuntu 了。你可以运行所有的 Ubuntu 原生命令或者 CLI 实用程序。Media我们来查看一下在你的目录下你拥有的所有 Docker 镜像:
$docker imagesREPOSITORY TAG IMAGE ID CREATED SIZEdockp latest 2a4cca5ac898 1 hour ago 111MBubuntu latest 2a4cca5ac898 1 hour ago 111MBhello-world latest f2a91732366c 8 weeks ago 1.85kB你可以看到共有三个镜像:dockp、Ubuntu、和 hello-world, hello-world 是我在几周前创建的,这一系列的前面的文章就是在它下面工作的。构建一个完整的 LAMP 栈可能是一个挑战,因此,我们使用 Dockerfile 去创建一个简单的 Apache 服务器镜像。从本质上说,Dockerfile 是安装所有需要的包、配置、以及拷贝文件的一套指令。在这个案例中,它是安装配置 Apache 和 Nginx。你也可以在 DockerHub 上去创建一个帐户,然后在构建镜像之前登入到你的帐户,在这个案例中,你需要从 DockerHub 上拉取一些东西。从命令行中登入 DockerHub,运行如下所求的命令:
$ docker login在登入时输入你的用户名和密码。接下来,为这个 Docker 项目,在目录中创建一个 Apache 目录:
$ mkdir apache在 Apache 目录中创建 Dockerfile 文件:
$ nano Dockerfile然后,粘贴下列内容:
FROM ubuntuMAINTAINER Kimbro Staken version: 0.1RUN apt-get update && apt-get install -y apache2 && apt-get clean && rm -rf /var/lib/apt/lists/*ENV APACHE_RUN_USER www-dataENV APACHE_RUN_GROUP www-dataENV APACHE_LOG_DIR /var/log/apache2EXPOSE 80CMD ["/usr/sbin/apache2", "-D", "FOREGROUND"]然后,构建镜像:
docker build -t apache .(注意命令尾部的空格和圆点)这将花费一些时间,然后你将看到如下的构建成功的消息:
Successfully built e7083fd898c7Successfully tagged ng:latestSwapnil:apache swapnil$现在,我们来运行一下这个服务器:
$ docker run -d apachea189a4db0f7c245dd6c934ef7164f3ddde09e1f3018b5b90350df8be85c8dc98发现了吗,你的容器镜像已经运行了。可以运行如下的命令来检查所有运行的容器:
$ docker psCONTAINER ID IMAGE COMMAND CREATEDa189a4db0f7 apache "/usr/sbin/apache2ctl" 10 seconds ago你可以使用 docker kill 命令来杀死容器:
$docker kill a189a4db0f7正如你所见,这个 “镜像” 它已经永久存在于你的目录中了,而不论运行与否。现在你可以根据你的需要创建很多的镜像,并且可以从这些镜像中繁衍出来更多的镜像。这就是如何去创建镜像和运行容器。想学习更多内容,你可以打开你的浏览器,然后找到更多的关于如何构建像 LAMP 栈这样的完整的 Docker 镜像的文档。这里有一个帮你实现它的 Dockerfile 文件。在下一篇文章中,我将演示如何推送一个镜像到 DockerHub。你可以通过来自 Linux 基金会和 edX 的 “介绍 Linux” 免费课程来学习更多的知识。via: https://www.linux.com/blog/learn/intro-to-linux/2018/1/how-create-docker-image作者:SWAPNIL BHARTIYA 译者:qhwdw 校对:wxy本文由 LCTT 原创编译,Linux中国 荣誉推出Media
via https://linux.cn/article-9541-1.html?utm_source=rss&utm_medium=rss
为初学者提供的 uniq 命令教程及示例
该命令会帮助你轻松地从文件中找到重复的行。它不仅用于查找重复项,而且我们还可以使用它来删除重复项,显示重复项的出现次数,只显示重复的行,只显示唯一的行等。Media
via https://linux.cn/article-9542-1.html
该命令会帮助你轻松地从文件中找到重复的行。它不仅用于查找重复项,而且我们还可以使用它来删除重复项,显示重复项的出现次数,只显示重复的行,只显示唯一的行等。Media
via https://linux.cn/article-9542-1.html
在树莓派上运行 DOS 系统
不同的 CPU 架构意味着在树莓派上运行 DOS 并非唾手可得,但其实也没多麻烦。Media
via https://linux.cn/article-9544-1.html
不同的 CPU 架构意味着在树莓派上运行 DOS 并非唾手可得,但其实也没多麻烦。Media
via https://linux.cn/article-9544-1.html
如何在 Windows 10 上开启 WSL 之旅
WSL 可以让你访问 Windows 上的 Linux Bash shell。Media
via https://linux.cn/article-9545-1.html
WSL 可以让你访问 Windows 上的 Linux Bash shell。Media
via https://linux.cn/article-9545-1.html