云计算课程实验
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

477 line
19 KiB

  1. # Assignment 2 指南
  2. ## `******注意,实验结束请立即删除云主机,节省费用******`
  3. ## `******注意2,实验未结束且短期内不会继续实验,也请删除云主机。下次实验时重新创建******`
  4. ### 重要技巧:如果实验未结束,可以通过制作主机镜像来保存当前状态,下次实验时用这个镜像创建云主机,从当前状态开始继续实验。步骤如下
  5. - 关机并制作镜像。制作完成后删除云主机。![关机](img/assignment2/关机.png)![镜像](img/assignment2/镜像.png)
  6. - 下次从镜像创建云主机。![创建](img/assignment2/创建.jpeg)
  7. ## 实验内容
  8. - 安装Docker并测试:`实验步骤 一)`
  9. - 了解并学习简单的Docker指令:`实验步骤 二)`
  10. - 利用Docker部署一个简单的静态网页App :`实验步骤 三)`
  11. - 使用Dockerfile完成复杂应用的搭建:`实验步骤 四)`
  12. ## 实验要求(仔细看)
  13. - #### 完成所有步骤,并在实验报告([模板下载](file/assignment2/学号-实验二.docx))中完成穿插在本指南中的`作业1~作业4`(只需要截图)。实验报告上传至 https://send2me.cn/BE8lksd_/SFW2bPQc78aR-g
  14. - #### 实验报告上传deadline:`9月29日23:59`
  15. ## 使用产品
  16. 云主机uhost, 私有网络vpc,基础网络unet, 容器镜像库uHub
  17. ## 需要权限
  18. 云主机uhost, 基础网络unet,容器镜像库uhub,容器服务udocker
  19. ## 实验步骤
  20. ### 零)前期工作
  21. #### 请根据Assignment1的要求[创建云主机](Assignment1.md),并使用ssh远程登录(可以直接使用root用户进行后续操作;如果登录个人账户进行操作,遇到permission问题时需在命令前面加上sudo再运行)
  22. #### `Hint(重要):` 本实验需要访问云主机的host端口,请在本地使用`-L `命令将云主机的`32768、32769、8000、8080`四个端口映射到本地,具体命令可以参考如下:
  23. ```bash
  24. $ ssh root@你的云主机外网ip -L 32769:0.0.0.0:32769 -L 32768:0.0.0.0:32768 -L 8080:0.0.0.0:8080 -L 8000:0.0.0.0:8000
  25. ```
  26. ### 一)安装Docker并测试
  27. #### 1. Docker是什么?
  28. > 一个开放源代码项目,通过在Linux上提供**OS级虚拟化**的附加抽象层和自动化层,使**容器**内软件应用程序的部署自动化。
  29. #### 简单来说,Docker是一种工具,它使开发人员,系统管理员等可以轻松地在沙盒(称为*容器*)中部署其应用程序,以在主机操作系统运行。Docker的主要好处是,它允许用户将**具有所有依赖关系的应用程序打包到**用于软件开发**的标准化单元**中。与虚拟机不同,容器不具有高开销,因此可以更有效地利用基础系统和资源。
  30. #### 2. 在Linux上安装Docker环境
  31. > 直到几个版本之前,在OSX和Windows上运行Docker还是很麻烦的。但是,最近,Docker已投入大量资金来改善其用户在这些OS上的体验,因此,现在运行Docker是一个轻而易举的事。
  32. #### 这里只介绍如何在Linux上安装和运行Docker, 如果同学们想要在其他系统上尝试使用Docker,可以参考Docker官网给出的教程(如何在[Mac](https://docs.docker.com/docker-for-mac/install)、[Linux/Ubuntu](https://docs.docker.com/install/linux/docker-ce/ubuntu)或[Windows]([Windows](https://docs.docker.com/docker-for-windows/install))上使用Docker)
  33. 在安装 docker 时,除了本文档提供的方法,也可以访问 https://docs.docker.com/engine/install/centos/ 按照官方教程进行安装。
  34. #### a) 安装docker
  35. #### 推荐使用如下命令安装 docker
  36. ```bash
  37. $ curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
  38. ```
  39. #### 如果遇到如下图所示错误,请先运行下面的命令后再重新安装 docker
  40. ```bash
  41. $ yum install -y https://download.docker.com/linux/centos/7/x86_64/stable/Packages/containerd.io-1.2.6-3.3.el7.x86_64.rpm
  42. ```
  43. ![docker错误](img/assignment2/docker错误.jpeg)
  44. #### 按照提示将自己的用户加入docker的用户组(root 用户无需操作)
  45. ```bash
  46. $ sudo usermod -aG docker yourusername
  47. ```
  48. #### 基本的docker启动与查看状态命令如下
  49. ```bash
  50. $ service docker start
  51. $ service docker stop
  52. $ service docker restart
  53. $ service docker status
  54. ● docker.service - Docker Application Container Engine
  55. Loaded: loaded (/usr/lib/systemd/system/docker.service; disabled; vendor preset: disabled)
  56. Active: active (running) since Mon 2020-10-05 21:34:37 CST; 1min 45s ago
  57. Docs: https://docs.docker.com
  58. Main PID: 1954 (dockerd)
  59. Tasks: 8
  60. Memory: 40.1M
  61. CGroup: /system.slice/docker.service
  62. └─1954 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
  63. ```
  64. ## **为保证试验正常进行,请根据以下步骤修改docker镜像源从默认镜像库改为ucloud镜像库**
  65. ### hint:docker镜像库中包含大量可用镜像,可以直接下载到本地使用,常用的镜像库比如https://hub.docker.com/
  66. #### 1.在 https://cloud.docker.com , 免费注册一个 Docker 账号。用以下命令登录`docker hub`,输入创建账号的用户名、密码
  67. ```bash
  68. $ docker login
  69. Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
  70. Username: linlinshe
  71. Password:
  72. WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
  73. Configure a credential helper to remove this warning. See
  74. https://docs.docker.com/engine/reference/commandline/login/#credentials-store
  75. Login Succeeded
  76. ```
  77. #### 出现`login succeeded`表示登陆成功
  78. #### 2.将如下内容写入`/etc/docker/daemon.json`中(没有此文件则需要新建. ps: 需保证`docker`已经运行过,否则会出现`/etc/docker`文件夹不存在)
  79. ```json
  80. {
  81. "registry-mirrors": ["https://uhub-edu.service.ucloud.cn","https://uhub.service.ucloud.cn","https://registry.docker-cn.com","http://hub-mirror.c.163.com"]
  82. }
  83. ```
  84. #### hint:可以使用`nano`命令直接在云主机上编辑daemon.json,使用方法请自行查找。也可以在本地用纯文本编辑器(如txt)编辑,然后上传到云主机。
  85. #### 之后重新启动`docker`即可
  86. #### b) 测试Docker是否安装成功
  87. #### 当你的按照上述步骤安装完docker之后,可以通过运行如下命令来测试docker是否安装成功
  88. ```bash
  89. $ docker run hello-world
  90. Hello from Docker.
  91. This message shows that your installation appears to be working correctly.
  92. ...
  93. ```
  94. 如果 docker run 报错,可以尝试先 `docker pull hello-world` 拉取镜像以后再 docker run 。
  95. #### 3. 尝试使用busybox
  96. > 到此为止,你的docker环境已经安装完成并且正常运行,接下来我们尝试一些更加复杂的工作
  97. #### 在这个部分,我们将要通过`docker run`命令去开启一个`BusyBox container`
  98. #### a) 首先,我们通过运行如下命令从镜像库拉取`BusyBox`的镜像:
  99. ```bash
  100. $ docker pull busybox
  101. ```
  102. > 如果运行过程中遇到 **permission denied** 此类的错误,可以尝试在命令前加入 **sudo** 命令
  103. #### b) **pull** 命令可以将`busybox image`从docker仓库中拉取到本地,你可以使用**docker image**命令查看系统上目前已有的**image**.
  104. ```bash
  105. $ docker images
  106. REPOSITORY TAG IMAGE ID CREATED VIRT
  107. busybox latest c51f86c28340 4 weeks ago 1.10
  108. ```
  109. #### c) 我们接下来继续尝试使用`docker run`命令来运行`busybox`
  110. ```bash
  111. $ docker run busybox
  112. $
  113. ```
  114. #### d) 可以发现命令运行完,什么也没有发生。这不是bug,当我们执行`docker run`命令时,docker会从本地查找`image`,然后加载`image`生成`container`容器,并在其中运行command。正因为我们没有运行任何command,此容器没有任何输出。让我们加入自定义的command再试一次。
  115. ```bash
  116. $ docker run busybox echo "hello from busybox"
  117. hello from busybox
  118. ```
  119. ##### hint:通常,docker image不在运行时叫image,加载运行以后叫container
  120. `**************作业1:请将上述涉及docker run/image的操作界面截图,并插入实验报告中***************`
  121. ### 二) 熟悉Docker指令
  122. #### 让我们来尝试不同的**docker command**
  123. #### 1. docker ps
  124. > **docker ps** 命令可以查看当前正在运行的所有容器的状态,包括`CONTAINER ID`、`IMAGE`、`COMMAND`、`CREATE (创建时间)`、`STATUS (容器状态)`
  125. #### 让我们查看目前有哪些容器正在运行
  126. ```bash
  127. $ docker ps
  128. CONTAINER ID IMAGE COMMAND CREATED STATUS
  129. ```
  130. #### 可以看到控制台输出了了一个空的列表,这是正常的,因为目前没有容器正在运行。如果需要查看包括不在运行的所有容器,我们可以加入 **-a** 参数
  131. ```bash
  132. $ docker ps -a
  133. CONTAINER ID IMAGE COMMAND CREATED STATUS
  134. 305297d7a235 busybox "uptime" 11 minutes ago Exited (
  135. ff0a5c3750b9 busybox "sh" 12 minutes ago Exited (
  136. 14e5bd11d164 hello-world "/hello" 2 minutes ago Exited (
  137. ```
  138. #### Wow~ 之前运行过的容器全部都出现在输出中了~
  139. #### 2. docker run -it
  140. > **docker run -it** 可以在我们创建 **container** 的同时,以交互式的形式获取到 **container shell** 的控制权. 我们可以在**docker run **命令中使用**--name custom_name** 来指定container的名称,若不指定,docker会为我们随机生成一个名字
  141. #### 接下来我们使用 **run -it** 命令来创建一个 `busybox container`,并在其中运行几个linux命令(回想:容器是一个虚拟化的环境,里面也运行了一个"轻量级的操作系统")
  142. ```bash
  143. $ docker run -it busybox sh
  144. / # ls
  145. bin dev etc home proc root sys tmp usr var
  146. / # uptime
  147. 05:45:21 up 5:58, 0 users, load average: 0.00, 0.01, 0.04
  148. / # cd home && pwd
  149. /home
  150. / # exit
  151. ```
  152. #### 3. docker rm
  153. > **docker rm -args** 可以删除不在运行的**container**,`args`可以是**container name/id** (可以不写完整,但必须保证唯一)
  154. #### 下面让我们尝试删除上面的两个**busybox container**
  155. ```bash
  156. $ docker rm 305297d7a235 ff0a5c3750b9
  157. 305297d7a235
  158. ff0a5c3750b9
  159. ```
  160. #### 也可以通过如下命令删除
  161. ```bash
  162. $ docker rm 305 ff
  163. 305297d7a235
  164. ff0a5c3750b9
  165. ```
  166. #### 现在使用`ps`命令检查一下是否删除成功吧!
  167. `**************作业2:请手动创建centos image的container,将终端命令和`container cpu`信息截图,并插入实验报告中***************`
  168. > Hint1: image名称即为centos
  169. > Hint2: 可以使用**lscpu**命令在container中查看linux的硬件信息,显示界面大致如下
  170. ```bash
  171. $ lscpu
  172. Architecture: x86_64
  173. CPU op-mode(s): 32-bit, 64-bit
  174. Byte Order: Little Endian
  175. CPU(s): 4
  176. On-line CPU(s) list: 0-3
  177. Thread(s) per core: 1
  178. Core(s) per socket: 1
  179. Socket(s): 4
  180. Vendor ID: GenuineIntel
  181. CPU family: 6
  182. Model: 158
  183. Model name: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
  184. Stepping: 9
  185. CPU MHz: 2800.000
  186. BogoMIPS: 5616.00
  187. L1d cache: 32K
  188. L1i cache: 32K
  189. L2 cache: 256K
  190. L3 cache: 6144K
  191. ...
  192. ```
  193. ### 三) 使用docker创建静态webapp
  194. #### `docker`与虚拟机不同之处在于,在部署复杂的应用时,`docker`可以灵活的从`docker hub`中`pull`各种`image`(如:`mysql`、`sqlserver`、`java`、`php`.etc.),并将它们自由的组合到一起,使得每个`container`都能发挥自己独特的作用。那么我们先从简单的部署单页面的静态网页开始吧!
  195. #### 1. 运行`static-web app`
  196. #### `docker hub`上有许多开发者们上传的`image`,我们可以自由下载并且使用,这里我们使用到的`image`是`cloud_computing/static_site`,这是一个搭载了简单的静态单页面的Nginx镜像,让我们来试者运行它:
  197. ```bash
  198. $ docker run --rm cloud_computing/static_site
  199. Nginx is running...
  200. ```
  201. > `--rm` 参数的作用是当container运行结束时系统自动删除该container
  202. #### 如果顺利的话,你的终端会出现`nginx is running...`,但是目前容器对我们来说是一个完全封闭的环境,我们并没有办法去访问`container`的端口。按'ctrl+c'可以结束并退出容器。
  203. #### 2. 将`container`映射到本地
  204. 到此为止,我们已经部署了一个静态的`nginx container`但是并没有办法去访问,`docker`提供了许多接口去解决这个问题,我们可以通过添加参数的方式将`container`的端口或者文件夹映射到本地
  205. #### docker提供了如下一些参数
  206. | -d | 将container置于后台运行 |
  207. | :---------------------------: | :----------------------------------------------------------: |
  208. | -p local_port:container_port | 将container 的某个端口映射到本地 |
  209. | -P | 将container所有正在监听的端口全部映射到本地的随机端口 |
  210. | -v local_path:contatiner_path | 将本地的local_path文件夹映射到container的container_path文件夹并保持同步 |
  211. `**关于-v参数的说明,当你使用到-v 参数时,如**`
  212. ```bash
  213. docker run -d -v /home/data:/var/data --name test ubuntu
  214. ```
  215. `**那么相当于你将本地的/home/data目录映射到container的/var/data目录,container的/var/data目录会和你的本地目录保持同步,同时,若/var/data目录不存在,docker会自动创建,反之,目录中的内容会被全部覆盖掉(和本地的/home/data保持同步),希望同学们好好理解**`
  216. #### `static-site`默认监听的`80`和`443`端口我们使用上述参数尝试将它映射到本机
  217. ```bash
  218. $ docker run -d -P --name static_site cloud_computing/static_site
  219. e61d12292d69556eabe2a44c16cbd54486b2527e2ce4f95438e504afb7b02810
  220. ```
  221. #### 查看docker给我们映射的端口
  222. ```
  223. $ docker port static_site
  224. 80/tcp -> 0.0.0.0:32769
  225. 443/tcp -> 0.0.0.0:32768
  226. ```
  227. #### 可以看到`docker`将`container`的`80`和`443`分别映射到了本机的`32769`和`32768`两个端口上
  228. #### 3.打开浏览器,访问`http://localhost:32769`,得到如下页面:(若`docker`随机映射端口不是`32768/32769`可以无需验证此步骤)
  229. ![static-web](img/assignment2/static-web.png)
  230. `**************作业3:尝试使用-v、--rm和-p (请将container的80端口映射到host的8000端口)等参数,创建cloud_computing/static_site容器,并按照下述步骤6的要求截图,插入实验报告中***************`
  231. #### 具体步骤如下:
  232. #### 1.若提示continer正在运行中,可以使用`docker stop static_site && docker rm static_site`删除正在使用的容器并重新创建.
  233. #### 2. 创建`/var/html`文件夹
  234. ```bash
  235. mkdir /var/html
  236. ```
  237. #### 3.在`/var/html`中新建`index.html`文件,复制[index.html文件](file/assignment2/index.html)中的内容到文件中,并修改以下部分为自己的信息
  238. ```html
  239. <div class="container">
  240. <div class="row">
  241. <div class="one-half column" style="margin-top: 25%">
  242. <h4>Hello Docker!</h4>
  243. <p>This is being served from a <strong>docker</strong> container running Nginx.</p>
  244. <p>my id is xxxx,my name is xxx</p>
  245. </div>
  246. </div>
  247. </div>
  248. ```
  249. #### 4. 尝试使用`-p、-v、-d、--rm、--name`参数创建`cloud_computing/static_site`的`container`,具体要求为:映射`container`的`80`端口到`host`的`8000`端口,映射`container`的`/usr/share/nginx/html/mypage`路径到`/var/html`文件夹,`container`名称以自己的学号命名
  250. #### 5.访问本地浏览器:`http://localhost:8000/mypage/index.html`,若该端口访问不了,可查看ucloud防火墙查看是否开放了该端口号。若未开放,则可创建防火墙,设置所需的开放端口
  251. #### 6.将浏览器界面包括url截图,将创建container的终端界面截图,并插入到实验报告中 (浏览器界面类似下面图片所示)
  252. ![浏览器界面](img/assignment2/static-web-2-1.png)
  253. ### 四) 熟悉Dockerfile的简单使用
  254. #### 到现在为止,同学可能会疑惑,这种docker的镜像到底是如何创建的呢?这里就要使用到一个概念: `Dockerfile`
  255. #### 1.从repo中下载[附件](file/assignment2/demo2.zip),通过在本地运行`scp`命令上传到云服务器并解压
  256. ```bash
  257. $ scp -r path\demo.zip root@113.31.105.65:~
  258. root@113.31.105.65's password:
  259. demo.zip 100% 1308 142.4KB/s 00:00
  260. $ unzip demo.zip
  261. Archive: demo.zip
  262. creating: demo/
  263. inflating: __MACOSX/._demo
  264. inflating: demo/Dockerfile
  265. inflating: demo/app.py
  266. ```
  267. #### 2.查看Dockerfile
  268. #### 这是一个`Flask App`,是一个用`python`写的网页应用,我们进入`demo`文件夹,只有两个文件`app.py、Dockerfile`
  269. #### 首先我们使用`cat app.py`命令查看`app.py`的内容,显示如下:
  270. ```python
  271. from flask import Flask
  272. app = Flask(__name__)
  273. @app.route('/')
  274. def hello():
  275. return 'hello world!'
  276. if __name__ == '__main__':
  277. app.run(host='0.0.0.0')
  278. ```
  279. #### 看不懂没有关系,这就是一个很简单的flask应用,它定义了一个路由,当我们访问:`http://localhost:5000/`的时候,浏览器会给我们返回`hello world!`
  280. #### 接下来我们继续查看`Dockerfile`:
  281. ```dockerfile
  282. # 拉取python镜像作为基本环境
  283. FROM cloud_computing/python:latest
  284. # 设置额外信息
  285. LABEL description="Dockerfile Demo for ECNU"
  286. # 在container中运行命令(这一步在container安装pip依赖)
  287. RUN pip install flask -i https://pypi.tuna.tsinghua.edu.cn/simple
  288. # 将本地目录拷贝到container并且设置为工作目录
  289. ADD ./app.py /opt
  290. WORKDIR /opt
  291. # 将5000端口暴露出来
  292. EXPOSE 5000
  293. # 容器启动的执行命令
  294. CMD python app.py
  295. ```
  296. #### 可以看出`Dockerfile`的书写非常简单易懂,涉及到几个命令
  297. | FROM | 指定容器来自的镜像 |
  298. | :-----: | :----------------------------------------------------------: |
  299. | RUN | 容器中运行shell命令 |
  300. | ADD | 将本地文件传送到容器指定位置 |
  301. | WORKDIR | 将容器中某个目录设置为工作目录(当前目录) |
  302. | EXPOSE | 将容器中某个端口暴露出来(如上述flask工作在5000端口,将其暴露出来) |
  303. | CMD | 容器启动自动执行的shell命令 |
  304. | LABEL | 设置一些额外的信息 |
  305. #### 通过`dockerfile`的方式,我们就可以将各种各样的环境打包成镜像上传到`docker hub`上供他人使用
  306. #### 3.打包镜像
  307. #### 在当前目录(`Dockerfile`同级目录),执行如下命令,`docker`会自动将当前环境部署打包为一个`image`
  308. ```bash
  309. $ docker build -t user-name/image-name .
  310. ```
  311. #### 通过上面的命令,我们就在本地打包好了一个名叫`username/image-name`的镜像,可以通过`docker images`命令查看是否创建成功。我们可以通过之前学习的`docker run`命令去创建该镜像的`container`
  312. `**************作业4:利用dockerfile将当前环境打包为 `英文姓名/demo` 的`image`,并通过`docker`命令将创建该镜像的`container`,将`5000`端口映射到本地的`8080`端口。将打包镜像的命令、创建容器的命令以及浏览器页面截图,并插入实验报告中***************`