技术流ken

运维拯救世界

Docker端口映射及创建镜像演示(二)–技术流ken

前言

 

在上一篇博客《Docker介绍及常用操作演示–技术流ken》中,已经详细介绍了docker相关内容以及有关镜像和容器的使用命令演示。

现在我们已经可以自己下载镜像,以及创建容器了。

但是现在有这样一个问题,我们创建的容器可以被其他人或者另外一台服务器访问吗?

基于上一篇博客中容器的创建,那样的容器是不能被其他服务器进行访问的,只能在宿主机进行访问。

想要实现被其他服务器访问,就要用到本篇博客写的内容了,有关docker中的虚拟网络。

另外,本篇博客将会介绍一种简单制作镜像的命令,以便我们能够制作自己的镜像。

 

Docker暴露容器方法

 

第一种:将容器中的一个端口映射成宿主机中的一个随机端口

第二种:将容器中的一个端口映射成宿主机中的一个端口

第三种:将容器中的一个端口映射成宿主机中的一个特定网卡上的随机端口

第四种:将容器中的一个端口映射成宿主机中的一个特定网卡上的一个端口

【使用多次-p选项可以实现暴露多个端口】

 

Docker端口映射的四种方法使用演示

 

第一种:将容器中的一个端口映射成宿主机中的一个随机端口

下面的操作确保虚拟机是在桥接模式

第一步:下载httpd镜像

[root@ken ~]# docker pull httpd
[root@ken ~]# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
httpd               latest              2a51bb06dc8b        12 days ago         132MB
redis               latest              55cb7014c24f        5 months ago        83.4MB

 

第二步:启动httpd容器

–name: 指定容器名

-d: 后台运行

-P: 大写的P,映射随机端口(暴露容器内所有端口,映射到宿主机的随机端口)

–rm: 表示退出容器时删除容器

[root@ken ~]# docker container run --name httpd1 -d -P --rm  httpd

 

第三步:查看端口

可以发现容器内的80端口被指向了宿主机的32768端口

[root@ken ~]# docker container ps
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                   NAMES
b02a0dd47b7b        httpd               "httpd-foreground"   25 seconds ago      Up 20 seconds       0.0.0.0:32768->80/tcp   httpd1

查看宿主机是否有32768端口

[root@ken ~]# ss -tnl | grep 32768
LISTEN     0      1024        :::32768                   :::*

 

第四步:访问

输入宿主机的IP地址加映射的端口号

通过以上的方法就可以实现外部主机访问一个容器了。

 

 第二种:将容器中的一个端口映射成宿主机中的一个端口

第一步:启动httpd容器

–name:指定容器名称

-d:后台运行

-p:小写的p指定端口,123为宿主机端口,80为容器的端口

–rm:退出容器及删除容器

[root@ken ~]# docker container run --name httpd2 -d -p 1234:80 --rm httpd

 

第二步:查看端口

[root@ken ~]# docker container ps 
CONTAINER ID        IMAGE               COMMAND              CREATED              STATUS              PORTS                 NAMES
e083fd2915a7        httpd               "httpd-foreground"   About a minute ago   Up About a minute   0.0.0.0:1234->80/tcp   httpd2
[root@ken ~]# ss -tnl | grep 1234
LISTEN     0      1024        :::1234                    :::*

 

第三步:访问

输入宿主机IP地址和设置的端口即可访问

 

第三种:将容器中的一个端口映射成宿主机中的一个特定网卡上的随机端口

第一步:启动httpd容器

指定特定的网卡需要使用小p 后面加上 网卡ip::容器端口

[root@ken ~]# docker container run --name httpd3 -d -p 10.220.5.13::80 --rm httpd

 

第二步:查看端口

可以看到下面生成了一个随机端口32768

[root@ken ~]# docker container ps 
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                       NAMES
63060c0e83f0        httpd               "httpd-foreground"   7 seconds ago       Up 5 seconds        10.220.5.13:32768->80/tcp   httpd3
[root@ken ~]# ss -tnl | grep 32768
LISTEN     0      1024   10.220.5.13:32768                    *:*

 

第三步:访问

使用生成的随机端口加上IP 地址即可进行容器的访问

 

第四种:将容器中的一个端口映射成宿主机中的一个特定网卡上的一个端口

第一步:启动容器

指定特定的网卡需要使用小p 后面加上 网卡ip:宿主机端口:容器端口

这里我指定了使用宿主机的8080端口进行容器端口的映射

[root@ken ~]# docker container run --name httpd3 -d -p 10.220.5.13:8080:80 --rm httpd

 

第二步:查看端口

[root@ken ~]# docker container ps
CONTAINER ID        IMAGE               COMMAND              CREATED             STATUS              PORTS                      NAMES
2a30717c6df7        httpd               "httpd-foreground"   57 seconds ago      Up 56 seconds       10.220.5.13:8080->80/tcp   httpd3
[root@ken ~]# ss -tnl | grep 8080
LISTEN     0      1024   10.220.5.13:8080                     *:*

 

第三步:浏览器访问

只要输入ip:端口即可进行访问

 

如果想要暴露一个容器内的多个端口可以使用多个-p

 

端口映射分析

 

每一个映射的端口,host 都会启动一个 docker-proxy 进程来处理访问容器的流量:

[root@ken3 ~]# ps aux | grep docker-proxy
root       3414  0.0  0.1 364368  7040 ?        Sl   22:29   0:00 /usr/bin/docker-proxy -proto tcp -host-ip 0.0.0.0 -host-port 56 -container-ip 172.17.0.3 -container-port 80

 

以 0.0.0.0:32773->80/tcp 为例分析整个过程:

  1. docker-proxy 监听 host 的 32773 端口。
  2. 当 curl 访问 10.0.2.15:32773 时,docker-proxy 转发给容器 172.17.0.2:80。
  3. httpd 容器响应请求并返回结果。

 

底层依然是iptables

[root@ken3 ~]# iptables -t nat -S
-P PREROUTING ACCEPT
-P INPUT ACCEPT
-P OUTPUT ACCEPT
-P POSTROUTING ACCEPT
-N DOCKER
-A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
-A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
-A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
-A POSTROUTING -s 172.18.0.0/16 ! -o br-060b813f7eeb -j MASQUERADE
-A POSTROUTING -s 192.168.6.0/24 ! -o br-1f44876ac489 -j MASQUERADE
-A POSTROUTING -s 172.17.0.3/32 -d 172.17.0.3/32 -p tcp -m tcp --dport 80 -j MASQUERADE
-A DOCKER -i docker0 -j RETURN
-A DOCKER -i br-060b813f7eeb -j RETURN
-A DOCKER -i br-1f44876ac489 -j RETURN
-A DOCKER ! -i docker0 -p tcp -m tcp --dport 56 -j DNAT --to-destination 172.17.0.3:80

 

 

项目

1.使用docker部署tomcat环境
2.上线网站
3.完成访问使用等

 

第一步:启动基于tomcat镜像的容器

[root@ken1 ~]# docker run -d -p 89:8080 kubeguide/tomcat-app:v1
b429c9ed543ffe3d7dfb6549ab528b843ea76776d737b76c51a073b348bcab34
[root@ken1 ~]# docker ps
CONTAINER ID        IMAGE                     COMMAND              CREATED             STATUS              PORTS                   NAMES
b429c9ed543f        kubeguide/tomcat-app:v1   "catalina.sh run"    3 seconds ago       Up 1 second         0.0.0.0:89->8080/tcp    interesting_babbage

 

第二步:清空容器tomcat网站根目录内容、

[root@ken1 ~]# docker exec -it b429c9ed543f  bash  #进入容器
root@b429c9ed543f:/usr/local/tomcat# ls #查看文件
LICENSE  NOTICE  RELEASE-NOTES	RUNNING.txt  bin  conf	include  lib  logs  temp  webapps  work
root@b429c9ed543f:/usr/local/tomcat# cd webapps/  #切换至tomcat网站根目录
root@b429c9ed543f:/usr/local/tomcat/webapps# ls  #查看是当前目录内容
ROOT  demo  docs  examples  host-manager  manager
root@b429c9ed543f:/usr/local/tomcat/webapps# cd ROOT  #切换至ROOT目录下
root@b429c9ed543f:/usr/local/tomcat/webapps/ROOT# ls
RELEASE-NOTES.txt  asf-logo.png   bg-nav-item.png  build.xml	tomcat-power.gif  tomcat.png
WEB-INF		   bg-button.png  bg-nav.png	   favicon.ico	tomcat.css	  tomcat.svg
asf-logo-wide.gif  bg-middle.png  bg-upper.png	   index.jsp	tomcat.gif
root@b429c9ed543f:/usr/local/tomcat/webapps/ROOT# rm -rf *  #删除ROOT下所有的内容

 

第三步:复制网站文件至tomcat网站根目录

[root@ken1 ~]# docker cp fuhai-jpress-alpha.zip b429c9ed543f:/usr/local/tomcat/webapps/ROOT

 

第四步:进入容器解压网站内容


root@b429c9ed543f:/usr/local/tomcat/webapps/ROOT# cd webapps/ROOT/
root@b429c9ed543f:/usr/local/tomcat/webapps/ROOT# ls
root@b429c9ed543f:/usr/local/tomcat/webapps/ROOT# unzip fuhai-jpress-alpha.zip 
root@b429c9ed543f:/usr/local/tomcat/webapps/ROOT# ls
root@b429c9ed543f:/usr/local/tomcat/webapps/ROOT# cp jpress/wars/jpress-web-newest.war  .
root@b429c9ed543f:/usr/local/tomcat/webapps/ROOT# ls
root@b429c9ed543f:/usr/local/tomcat/webapps/ROOT# unzip jpress-web-newest.war 
root@b429c9ed543f:/usr/local/tomcat/webapps/ROOT# ls
META-INF  WEB-INF  fuhai-jpress-alpha.zip  jpress  jpress-web-newest.war  robots.txt  static  templates

 

第五步:配置数据库

MariaDB [(none)]> create database jpress;
MariaDB [(none)]> grant all on *.* to jpress@'%' identified by '123';

 

第六步:浏览器再次访问网站 #数据库部署在宿主机之上!!!

填入数据库名

数据库用户及密码

输入数据库地址192.168.64.5

数据库端口3306

创建自己的镜像仓库

 

需要在阿里云创建镜像仓库

 

控制台–》镜像仓库

 

第一步:创建镜像仓库

点击创建镜像仓库

 

第二步:填写你的注册信息

 

第三步:点击本地仓库

 

第四步:如下就创建好了一个自己的镜像仓库

 

往阿里云仓库推送和拉取镜像:

1. 登录阿里云Docker Registry

$ sudo docker login --username=kenkendyg registry.cn-hangzhou.aliyuncs.com

用于登录的用户名为阿里云账号全名,密码为开通服务时设置的密码。

您可以在产品控制台首页修改登录密码。

2. 从Registry中拉取镜像

$ sudo docker pull registry.cn-hangzhou.aliyuncs.com/kenken/myself:[镜像版本号]

3. 将镜像推送到Registry

$ sudo docker login --username=kenkendyg registry.cn-hangzhou.aliyuncs.com$ sudo docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/kenken/myself:[镜像版本号]$ sudo docker push registry.cn-hangzhou.aliyuncs.com/kenken/myself:[镜像版本号]

请根据实际镜像信息替换示例中的[ImageId]和[镜像版本号]参数。

 

基于容器创建镜像

 

获取使用帮助

commit用来基于一个现有容器来创建镜像

[root@ken ~]# docker commit --help

Usage:    docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

Create a new image from a container's changes

 

参数详解

  -a,           作者信息 (e.g., "John Hannibal Smith <hannibal@a-team.com>")
  -c,           将Dockerfile指令应用于创建的映像 (default [])-m, --message string   
  -m            提交信息
  -p,           提交时暂停容器 (default true)

 

第一步:启动容器

[root@ken ~]# docker container run -it --name busybox1 busybox

 

第二步:创建则是页面

[root@ken ~]# docker container exec -it busybox1 /bin/sh
/ # mkdir /data
/ # echo "test for my image">/data/index.html
/ # httpd -h /data
/ #

 

第三步:基于容器创建镜像

[root@ken ~]# docker commit -a "ken" -p -c "CMD ["/bin/httpd","-f","-h","/data"]" busybox1 kenken/httpd1
sha256:29846cdbd83478bc9469b6ad25e76851655072bca6c984eeffedb52a8c8b91c0

 

第四步:查看镜像

可以看到第一个就是刚才创建的镜像

[root@ken ~]# docker image ls
REPOSITORY          TAG                 IMAGE ID            CREATED             SIZE
kenken/httpd1       latest              29846cdbd834        23 seconds ago      1.15 MB
docker.io/nginx     latest              568c4670fa80        16 hours ago        109 MB
docker.io/redis     latest              c188f257942c        12 days ago         94.9 MB
docker.io/httpd     latest              2a51bb06dc8b        12 days ago         132 MB
docker.io/busybox   latest              59788edf1f3e        8 weeks ago         1.15 MB

 

第五步:往阿里云推送

首先需要登录阿里云

输入的密码是注册的阿里云账号的密码

[root@ken ~]# docker login --username=kenkendyg registry.cn-beijing.aliyuncs.com
Password: 
Login Succeeded

 

第六步:给制作好的镜像打一个标签

29846cdbd834是你的镜像的ID
[root@ken ~]# docker tag 29846cdbd834 registry.cn-beijing.aliyuncs.com/kenken/httpd:v1

 

第七步:推送镜像

[root@ken ~]# docker push registry.cn-beijing.aliyuncs.com/kenken/httpd:v1
The push refers to a repository [registry.cn-beijing.aliyuncs.com/kenken/httpd]
b4a60ebae046: Pushed 
8a788232037e: Pushed 
v1: digest: sha256:88008e08275bc85dbbef8f770d66cdec5cf96e86e4ad5e2a38c5b5a8c1b2e57f size: 734

 

第八步:在阿里云查看

首先点击管理

点击镜像 版本即可查看

第九步:拉取阿里云镜像到本地

拉取镜像需要在另一台主机上面登录阿里云

[root@ken ~]#  docker login --username=kenkendyg registry.cn-beijing.aliyuncs.com
Password: 
Login Succeeded
[root@ken ~]# docker pull registry.cn-beijing.aliyuncs.com/kenken/httpd:v1
v1: Pulling from kenken/httpd
90e01955edcd: Already exists 
3d5cd4fa148f: Pull complete 
Digest: sha256:88008e08275bc85dbbef8f770d66cdec5cf96e86e4ad5e2a38c5b5a8c1b2e57f
Status: Downloaded newer image for registry.cn-beijing.aliyuncs.com/kenken/httpd:v1
[root@ken ~]# docker image ls
REPOSITORY                                      TAG                 IMAGE ID            CREATED             SIZE
registry.cn-beijing.aliyuncs.com/kenken/httpd   v1                  29846cdbd834        17 minutes ago      1.15MB
nginx                                           latest              568c4670fa80        17 hours ago        109MB
httpd                                           latest              2a51bb06dc8b        12 days ago         132MB
busybox                                         latest              59788edf1f3e        8 weeks ago         1.15MB
redis                                           latest              55cb7014c24f        5 months ago        83.4MB

实现容器的底层技术

 

为了更好地理解容器的特性,我们将讨论容器的底层实现技术。
cgroup 和 namespace 是最重要的两种技术。cgroup 实现资源限额, namespace 实现资源隔离。

cgroup

cgroup 全称 Control Group。Linux 操作系统通过 cgroup 可以设置进程使用 CPU、内存 和 IO 资源的限额。

cgroup 到底长什么样子呢?我们可以在 /sys/fs/cgroup 中找到它。还是用例子来说明,启动一个容器,设置内存为512M

在 /sys/fs/cgroup/memory/docker 目录中,Linux 会为每个容器创建一个 cgroup 目录,以容器长ID 命名:

 

对内存使用限制

Docker 可以通过 -c 或 –cpu-shares 设置容器使用 CPU 的权重。如果不指定,默认值为 1024。

与内存限额不同,通过 -c 设置的 cpu share 并不是 CPU 资源的绝对数量,而是一个相对的权重值。某个容器最终能分配到的 CPU 资源取决于它的 cpu share 占所有容器 cpu share 总和的比例

换句话说:通过 cpu share 可以设置容器使用 CPU 的优先级。

比如在 host 中启动了两个容器:

docker run –name “containerA” -c 1024 httpd

docker run –name “containerB” -c 512 httpd

containerA 的 cpu share 1024,是 containerB 的两倍。当两个容器都需要 CPU 资源时,containerA 可以得到的 CPU 是 containerB 的两倍。

需要特别注意的是,这种按权重分配 CPU 只会发生在 CPU 资源紧张的情况下。如果 containerA 处于空闲状态,这时,为了充分利用 CPU 资源,container_B 也可以分配到全部可用的 CPU。

 

可以在这里找到设置的cpu

[root@ken1 ~]# cat /sys/fs/cgroup/cpu/docker/a1f00b2682796ec9d0c64c8356645ecaeba95c622b4d306124c01d17fd9e5829/cpu.shares 
512

 

 

namespace

在每个容器中,我们都可以看到文件系统,网卡等资源,这些资源看上去是容器自己的。拿网卡来说,每个容器都会认为自己有一块独立的网卡,即使 host 上只有一块物理网卡。这种方式非常好,它使得容器更像一个独立的计算机。

Linux 实现这种方式的技术是 namespace。namespace 管理着 host 中全局唯一的资源,并可以让每个容器都觉得只有自己在使用它。换句话说,namespace 实现了容器间资源的隔离

Linux 使用了六种 namespace,分别对应六种资源:Mount、UTS、IPC、PID、Network 和 User,下面我们分别讨论。

 

Mount namespace

Mount namespace 让容器看上去拥有整个文件系统。

容器有自己的 / 目录,可以执行 mount 和 umount 命令。当然我们知道这些操作只在当前容器中生效,不会影响到 host 和其他容器。

 

UTS namespace

简单的说,UTS namespace 让容器有自己的 hostname。 默认情况下,容器的 hostname 是它的短ID,可以通过 -h 或 --hostname 参数设置。

 

 

IPC namespace

IPC namespace 让容器拥有自己的共享内存和信号量(semaphore)来实现进程间通信,而不会与 host 和其他容器的 IPC 混在一起。

 

PID namespace

容器在 host 中以进程的形式运行。容器内进程的 PID 不同于 host 中对应进程的 PID,容器中 PID=1 的进程当然也不是 host 的systemd进程。也就是说:容器拥有自己独立的一套 PID,这就是 PID namespace 提供的功能。

 

Network namespace

Network namespace 让容器拥有自己独立的网卡、IP、路由等资源。

 

User namespace

User namespace 让容器能够管理自己的用户,host 不能看到容器中创建的用户。

10 thoughts on “Docker端口映射及创建镜像演示(二)–技术流ken

  1. I抦 impressed, I have to say. Actually not often do I encounter a blog that抯 both educative and entertaining, and let me inform you, you have got hit the nail on the head. Your concept is excellent; the problem is one thing that not sufficient individuals are speaking intelligently about. I’m very pleased that I stumbled throughout this in my seek for something regarding this.

  2. Thanks so much for giving everyone an exceptionally special opportunity to read in detail from this website. It can be very beneficial and stuffed with fun for me personally and my office co-workers to visit your blog at the very least three times per week to find out the newest tips you have got. And lastly, I’m usually motivated with your brilliant strategies served by you. Certain 1 tips in this posting are really the very best we have ever had.

  3. I actually wanted to send a small note in order to say thanks to you for all of the superb solutions you are placing on this site. My considerable internet investigation has at the end of the day been paid with reliable points to write about with my partners. I ‘d claim that we readers actually are really fortunate to live in a magnificent community with so many marvellous professionals with valuable advice. I feel truly fortunate to have come across the website and look forward to so many more cool moments reading here. Thank you once more for all the details.

  4. Thanks a lot for giving everyone a very memorable chance to read critical reviews from here. It’s usually so superb and stuffed with a good time for me personally and my office friends to search the blog really three times in one week to read the fresh tips you will have. And indeed, I am just actually impressed for the awesome hints you serve. Certain 2 ideas in this article are ultimately the most impressive I have ever had.

  5. Thanks so much for providing individuals with an exceptionally memorable chance to read from this web site. It’s usually very kind plus packed with amusement for me personally and my office mates to visit your website a minimum of thrice in a week to learn the latest tips you have. And of course, I’m so certainly impressed with all the unique thoughts served by you. Certain 3 points in this post are ultimately the most suitable I’ve had.

  6. I am only writing to let you be aware of of the terrific encounter my girl encountered reading through yuor web blog. She came to understand a wide variety of issues, including how it is like to possess an ideal coaching spirit to have folks very easily understand a variety of tricky subject matter. You really surpassed readers’ desires. I appreciate you for coming up with the effective, safe, educational not to mention easy tips about your topic to Jane.

  7. Needed to post you one tiny remark to finally thank you again on the remarkable methods you have featured at this time. It’s strangely generous of people like you to grant extensively all numerous people could have marketed for an ebook in order to make some profit for their own end, primarily since you could have tried it if you decided. Those things as well acted to be a easy way to know that someone else have a similar desire really like mine to find out somewhat more around this problem. I’m sure there are thousands of more pleasurable situations ahead for many who read carefully your blog post.

  8. I would like to show thanks to the writer just for bailing me out of this type of condition. Just after surfing throughout the search engines and finding ideas which are not helpful, I assumed my entire life was done. Existing minus the approaches to the difficulties you’ve sorted out all through your main blog post is a serious case, and the ones that could have badly affected my entire career if I had not noticed your web blog. That talents and kindness in dealing with all the things was invaluable. I’m not sure what I would’ve done if I hadn’t come upon such a solution like this. It’s possible to now relish my future. Thanks for your time very much for this specialized and sensible help. I won’t think twice to propose the website to anyone who requires support on this topic.

  9. I just wanted to compose a small message to express gratitude to you for those splendid strategies you are writing on this website. My time-consuming internet search has at the end of the day been rewarded with wonderful insight to go over with my colleagues. I would mention that we readers are quite endowed to exist in a really good website with many marvellous people with helpful tactics. I feel rather happy to have used your site and look forward to some more fabulous moments reading here. Thanks once more for a lot of things.

  10. My spouse and i have been so glad that Jordan could complete his analysis because of the ideas he received out of the web pages. It’s not at all simplistic to simply always be giving away guides which often people could have been trying to sell. And we all take into account we’ve got you to be grateful to because of that. All of the explanations you made, the easy site navigation, the friendships you can assist to create – it is many extraordinary, and it’s aiding our son and us feel that that issue is satisfying, and that is highly fundamental. Thanks for all the pieces!

发表评论

电子邮件地址不会被公开。