How to Create and Access Container Cluster (Container Engine for Kubernetes) in Oracle Cloud

本文描述如何在Oracle Cloud中创建并访问容器服务。为了简单,所有的操作都是针对root compartment。

创建允许容器运行的Policy

这一步是必须的,否则不允许创建容器集群。
官方文档链接

左上角的产品菜单中:Governance and Administration -> Identity -> Policies
点击“Create Policy”之后,按照下图的样式创建Policy。
NewImage

创建容器集群

官方文档链接

左上角的产品菜单中:Solutions and Platform -> Developer Services -> Container Cluster(OKE)
NewImage

点击“Create Cluster”之后,页面中的元素较多,以下截图只是上半部分。
NewImage

虽然元素较多,但是在测试阶段可以几乎完全使用默认值。因此直接点“Create”就好。
在容器集群中的Worker Node可以不用ssh登录(我们在后续只需要通过oci和kubectl命令来操作集群就可以),所以页面中的PUBLIC SSH KEY确实是不用输入的,而默认的Private网络类型也无需修改。

创建容器集群需要花数分钟时间,创建成功以后,在集群页面就可以看到新创建的集群的详细信息。在我的测试里,指定了Node Pool里只有2台Node,不是默认的3台,因此在列表中只显示了两台机器。

NewImage

创建kubeconfig文件

官方文档链接

这一步比较繁琐。分为5个小步骤,不过官方文档中的描述很详尽。
NewImage

第一步:标准的生成访问密钥的过程

mkdir ~/.oci
openssl genrsa -out ~/.oci/oci_api_key.pem 2048
chmod go-rwx ~/.oci/oci_api_key.pem
openssl rsa -pubout -in ~/.oci/oci_api_key.pem -out ~/.oci/oci_api_key_public.pem
cat ~/.oci/oci_api_key_public.pem | pbcopy

第二步:在管理界面右上角的用户logo那里选择User Settings
NewImage

点击“Add Public Key”,直接将上一步生成的内容粘贴到输入框中,点“Add”。
NewImage

第三步:安装配置Oracle Cloud Infrastructure CLI
OCI CLI是一个命令行工具,就像Google Cloud也会提供gcloud命令行工具一样,这个工具用来在命令行里直接操纵Cloud中的各种资源。因为我们要用oci的create-kubeconfig命令来创建kubecongfig文件,所以需要这一步。

bash -c "$(curl -L https://raw.githubusercontent.com/oracle/oci-cli/master/scripts/install/install.sh)"

中间有一些需要输入的地方,也可以接受默认值一路回车。

运行完毕以后,显示successful。

-- Installation successful.
-- Run the CLI with /usr/local/bin/oci --help

安装完毕以后,必须先进行配置,才可以使用。

oci setup config

这一步配置要在Oracle Cloud的后台各个地方找到需要的信息(Tenancy UCID,User UCID,Region name),并且将值填入才可以。这里不一一赘述,在 官方文档中都有相应描述。

Enter a location for your config [/Users/Kamus/.oci/config]:
Enter a user OCID: "your user ocid here"
Enter a tenancy OCID: "your tenancy ocid here"
Enter a region (e.g. ap-mumbai-1, ap-seoul-1, ap-sydney-1, ap-tokyo-1, ca-toronto-1, eu-frankfurt-1, eu-zurich-1, sa-saopaulo-1, uk-london-1, us-ashburn-1, us-gov-ashburn-1, us-gov-chicago-1, us-gov-phoenix-1, us-langley-1, us-luke-1, us-phoenix-1): ap-tokyo-1
Do you want to generate a new RSA key pair? (If you decline you will be asked to supply the path to an existing key.) [Y/n]: n
Enter the location of your private key file: /Users/Kamus/.oci/oci_api_key.pem
Fingerprint: 5d:53:af:a8:d2:6b:4d:2f:20:24:b3:5b:c2:eb:89:86
Config written to /Users/Kamus/.oci/config

在最后一步问是否需要生成新的RSA key pair时选择n,因为我们在上面已经生成过了,这里只需要将本地的私钥地址填入即可。

这一步完毕以后,我们已经可以使用oci操纵Oracle Cloud中的资源了,比如我们列出在上面创建容器集群时自动创建的两个计算资源。

$ oci compute instance list -c “your-compartment-id”|grep "display-name"
      "display-name": "oke-cqwkmbzgbrd-nztqytbgjst-sxqablc2qgq-0",
      "display-name": "oke-cqwkmbzgbrd-nztqytbgjst-sxqablc2qgq-1",

oci命令行工具的完整文档参看这里

第四步:生成kubeconfig
oci工具只是操作Oracle Cloud中的基础资源,想要管理容器,还是要使用kubectl。为了让kubectl可以知道操纵哪里的容器集群,需要生成kubeconfig。

mkdir -p HOME/.kube
oci ce cluster create-kubeconfig --cluster-id “your-cluster-id” --file /Users/Kamus/.kube/config.oci --region ap-tokyo-1 --token-version 2.0.0 
export KUBECONFIG=HOME/.kube/config.oci

上述命令中的“your-cluster-id”可以在容器集群的信息页面中找到。
NewImage

至此,我们已经可以使用kubectl管理Oracle Cloud中的容器集群了。比如显示默认运行的所有pods。(当前,前提是已经安装了kubectl,如果还未安装,请参阅Kubernetes的官方安装文档

$ kubectl get pods --all-namespaces
NAMESPACE     NAME                                    READY   STATUS    RESTARTS   AGE
kube-system   kube-dns-7bcbdbdbcb-bdfdx               3/3     Running   0          65m
kube-system   kube-dns-7bcbdbdbcb-w8jm7               3/3     Running   0          60m
kube-system   kube-dns-autoscaler-7c6dd95548-9r9wv    1/1     Running   0          65m
kube-system   kube-flannel-ds-f2s6x                   1/1     Running   1          60m
kube-system   kube-flannel-ds-jzrjp                   1/1     Running   0          61m
kube-system   kube-proxy-btccr                        1/1     Running   0          60m
kube-system   kube-proxy-llh74                        1/1     Running   0          61m
kube-system   kubernetes-dashboard-74f74898c9-q9zpw   1/1     Running   0          65m
kube-system   proxymux-client-10.0.10.2               1/1     Running   0          60m
kube-system   proxymux-client-10.0.10.3               1/1     Running   0          61m
kube-system   tiller-deploy-6f8654fd88-xc229          1/1     Running   0          65m

总结:虽然通过kubectl管理Oracle Cloud中的容器集群前续需要的步骤较多,但是整体上而言还是比较顺畅的体验。

How to Connect SQL Developer to Oracle Autonomous Transaction Processing (ATP)

Autonomous Transaction Processing简称为ATP,是Oracle自治数据库在云上的一种表现形式,另外一种是Autonomous Data Warehouse,简称ADW。目前这两种Oracle数据库的云服务都在最新发布的Always Free Services中,也就是只需要在Oracle Cloud网站中注册一个免费用户,就可以永久免费使用一定规格的这两种服务。

实际上Oracle云的Always Free Services中包含的不仅仅是数据库,还提供了计算资源、存储资源和网络资源。使用这一整套永久免费的云服务,搭建一套完整的企业应用是OK的,完全可以用于研发环境、测试环境,甚至是最初的产品环境。
NewImage

那么具体到永久免费的数据库云服务,我们可以使用到的规格是:
1. 可以最多创建两个数据库环境,只有数据库,并不能接触到数据库在运行的主机,因为实际上只是两个PDB;
2. 每个PDB可以使用到最多1个OCPU,8GB内存,20GB存储容量;
3. 有一个额外的限制,最大的同时运行会话数不能超过20.

NewImage

具体的规格描述可以参看官方文档:https://docs.cloud.oracle.com/iaas/Content/FreeTier/resourceref.htm

好了,假设我们已经创建好了一个ATP数据库。那么首先要解决的是如何连接到这个数据库中,说Oracle是全球对于数据库安全最看重的公司其实不为过,连接Oracle ATP数据库(或者ADW数据库也一样)并没有像其它云中的数据库那么简单,只要开一个防火墙端口,给一个连接串就能连接上了。

实际上用Oracle SQL Developer连接原本是最简单的,但是会有一些错误要解决。

  • 下载最新的Oracle SQL Developer 19.2.1
  • 在Oracle Cloud管理后台下载连接ATP需要的wallet压缩文件。Oracle Cloud的UI做的是如此之复杂,入口繁多,期望你们能顺利找到这个页面。
    NewImage

点击“数据库连接”之后,会出现下载页面。
NewImage

点击“下载”按钮,会要求设置密码,实际上在使用SQL Developer连接数据库的时候并不需要此密码。因此可以随便设置。
下载的zip文件无需解压,将之放到任何一个合适的目录中即可。我放在了用户目录下的oracle目录中。

# Kamus @ Kamus-MacBook-Pro-2016 in ~/oracle [17:54:09]
$ ls *zip
Wallet_DB201909261518.zip
  • 打开SQL Developer,新增数据库连接,在连接类型中选择Cloud Wallet。如果你的SQL Developer不是最新版本,可能不是这样的称呼,所以还是请下载使用最新版本。
    NewImage
  • 如果你的机器安装的JAVA 8或者更早的版本,那么很可能会遇到这个错误。
    NewImage

点击错误中显示的链接地址,下载Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy文件,这个文件非常小,下载完毕以后解压,然后将解压出来的两个jar包:local_policy.jar和US_export_policy.jar,覆盖掉原JAVA环境中的同名文件。原来的文件位置在:$JAVA_HOME/jre/lib/security 中。比如在我的机器上,这个文件位于:

# Kamus @ Kamus-MacBook-Pro-2016 in /Library/Java/JavaVirtualMachines/jdk1.8.0_71.jdk/Contents/Home [18:08:58]
$ find . -name local_policy.jar
./jre/lib/security/local_policy.jar
  • 如果一切正常,再次打开SQL Developer并新增数据库连接,选择Cloud Wallet类型,就会出现以下界面了。
    NewImage

在(1)处直接选择在第2步中下载的wallet zip文件,在(2)处输入默认的管理用户ADMIN,和之前创建ATP服务时要求输入的ADMIN密码,期望你还记得。

  • 实际上如果我们解压wallet zip文件,就可以看到其中包含了tnsnames.ora,这其中Oracle Cloud为所有的数据库连接都预先定义好了5种连接串。
    NewImage

这5种不同的连接串,是联系到不同的resource manager计划中的,但是在我们目前初步连接数据库的时候,每种连接都是可以的。因此可以直接使用最上面的“_high”连接。

  • 保存然后连接数据库。
    NewImage

最后,ATP的官方文档链接在这里。关于连接数据库的部分在这里

How to login the VM of Docker Desktop for Mac

Docker for macOS的宿主机在哪里?

我们之前在MOVING MYSQL GROUP REPLICATION INSTANCES TO DOCKER CONTAINER ON MACOS这篇文章中提过在Docker for macOS中,容器的宿主机并不是macOS本身,而是在macOS中运行的一个虚拟机。虚拟机的路径可以通过查看Docker Desktop的配置界面获知。
NewImage

如果我们想登录这台虚拟机应该怎么做?

方法一

使用screen命令。实际上在上面那篇文章中我们提到过这个方法。
比如在上图中我们看到虚拟机的文件路径是:

/Users/Kamus/Library/Containers/com.docker.docker/Data/vms/0/Docker.raw

进入到这个文件的所在目录。可以看到tty这个软链接文件。

$ cd /Users/Kamus/Library/Containers/com.docker.docker/Data/vms/0
$ ls -l
total 31067864
srwxr-xr-x  1 Kamus  staff            0  7  4 12:22 00000002.000005f4
srwxr-xr-x  1 Kamus  staff            0  7  4 12:22 00000002.00001000
srwxr-xr-x  1 Kamus  staff            0  7  4 12:22 00000002.00001001
srwxr-xr-x  1 Kamus  staff            0  7  4 12:22 00000002.0000f3a5
srwxr-xr-x  1 Kamus  staff            0  7  4 12:22 00000003.000005f5
srwxr-xr-x  1 Kamus  staff            0  7  4 12:22 00000003.00000948
-rw-r--r--@ 1 Kamus  staff  63999836160  7  7 12:51 Docker.raw
-rw-r--r--  1 Kamus  staff       215040  7  4 12:22 config.iso
srwxr-xr-x  1 Kamus  staff            0  7  4 12:22 connect
lrwxr-xr-x  1 Kamus  staff           17  7  4 12:22 guest.000005f5 -> 00000003.000005f5
lrwxr-xr-x  1 Kamus  staff           17  7  4 12:22 guest.00000948 -> 00000003.00000948
-rw-r--r--  1 Kamus  staff         2303  7  4 12:22 hyperkit.json
-rw-r--r--  1 Kamus  staff            4  7  4 12:22 hyperkit.pid
drwxr-xr-x  2 Kamus  staff           64 11 21  2018 log
-rw-r--r--  1 Kamus  staff           36 11 21  2018 nic1.uuid
lrwxr-xr-x  1 Kamus  staff           12  7  4 12:22 tty -> /dev/ttys000

screen该文件即可连接到虚拟机的输出窗口中。

$ screen tty

screen之后可能终端界面会悬停,按一下Ctrl+c,即可显示出已经登录到了虚拟机中。

linuxkit-025000000001:~# uname -a
Linux linuxkit-025000000001 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 Linux

登出screen界面可以使用Ctrl+a d(同时按住Ctrl和a,然后放开再按下d),重新登入,可以使用screen -r,如果要彻底结束screen,可以使用Ctrl+a k。

方法二

还可以使用更优雅的方式,临时建一个最小化的debian容器,指定容器运行在pid=host命名空间下,然后该容器运行nsenter命令。如果之前没有安装过依赖的debian镜像,那么会首先自动下载这个镜像,镜像很小,只有101MB。

$ docker run -it --rm --privileged --pid=host debian nsenter -t 1 -m -u -n -i sh
Unable to find image 'debian:latest' locally
latest: Pulling from library/debian
6f2f362378c5: Pull complete
Digest: sha256:118cf8f3557e1ea766c02f36f05f6ac3e63628427ea8965fb861be904ec35a6f
Status: Downloaded newer image for debian:latest

/ # uname -a
Linux linuxkit-025000000001 4.9.125-linuxkit #1 SMP Fri Sep 7 08:20:28 UTC 2018 x86_64 Linux

如果说觉得101MB的debian镜像还是太大了,那么可以选择下载Alpine Linux镜像,这个镜像只有5.56MB。

$ docker run -it --rm --privileged --pid=host alpine:edge nsenter -t 1 -m -u -n -i sh

详细解释一下这条命令为什么就会登录进macOS中作为宿主机的VM里面。
–rm表示在退出的时候就自动删除该容器;
–privileged表示允许该容器访问宿主机(也就是我们想要登录的VM)中的各种设备;
–pid=host表示允许容器共享宿主机的进程命名空间(namespace),或者通俗点儿解释就是允许容器看到宿主机中的各种进程;
这些是docker在启动容器时候的参数设置,但是仅仅依靠这些参数还无法让我们直接登录到宿主机VM中,接下来解释最主要的nsenter命令。

nsenter是一个小工具允许我们进入一个指定的namespace然后运行指定的命令,ns=namespace,enter=进入。
namespace是容器技术的根基,基本上可以认为namespace就是一组隔离的资源,不同的进程可以看到不同的系统资源这里这里有比较详细的关于namespace的介绍。
可以从操作系统的/proc/[pid]/ns目录下一窥全貌。比如我们进入pid=1的ns目录下。可以看到有一共8种namespace。

# pwd
/proc/1/ns
# ls -l
total 0
lrwxrwxrwx 1 root root 0 Jul  8 12:51 cgroup -> cgroup:[4026531835]
lrwxrwxrwx 1 root root 0 Jul  8 12:51 ipc -> ipc:[4026531839]
lrwxrwxrwx 1 root root 0 Jul  8 12:51 mnt -> mnt:[4026531840]
lrwxrwxrwx 1 root root 0 Jul  8 12:51 net -> net:[4026531889]
lrwxrwxrwx 1 root root 0 Jul  8 12:51 pid -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Jul  8 12:51 pid_for_children -> pid:[4026531836]
lrwxrwxrwx 1 root root 0 Jul  8 12:51 user -> user:[4026531837]
lrwxrwxrwx 1 root root 0 Jul  8 12:51 uts -> uts:[4026531838]

接下来我们通过一个例子来直观的感受一下namespace和nsenter的功能,由于没有现成的操作系统命令可以修改一个namespace用于演示,所以我们需要先在nbrownuk下载一段c函数源码,我们演示UTS namespace,这个相对直观,所以只需要下载invoke_ns3.c即可。
UTS namespace中包含了hostname,我们的演示计划是给一个进程设置一个新的hostname,然后用nsenter进入该进程的namespace查看。

下载完invoke_ns3.c之后,需要编译。

# gcc -o invoke_ns3 ./invoke_ns3.c
# ls -l
total 28
-rwxr-xr-x 1 root root 71928 Jul  8 13:41 invoke_ns3
-rw-r--r-- 1 root root  4603 Jul  8 13:38 invoke_ns3.c

使用新的hostname启动一个bash进程,15842是执行invoke_ns3命令的进程,而15843则是bash进程,接下来我们只需要用nsenter进入15843进程验证一下即可。

# ./invoke_ns3 -vu newhostname bash
Parent: PID of parent is 15842
Parent: PID of child is 15843
 Child: PID of child is 15843
 Child: executing command bash ...
[root@newhostname root]

启动一个新的终端。可以看到在终端自己的hostname没有变化的情况下,我们用nsenter进入不同的进程,看到的hostname是不同的,其中15843进程中显示的就是上面修改过的主机名。

# hostname
ecs-arm-4xlarge
# nsenter -t 1 -u hostname
ecs-arm-4xlarge
# nsenter -t 15843 -u hostname
newhostname

最后解释一下nsenter命令的选项。回顾一下命令是:nsenter -t 1 -m -u -n -i sh
-t 1: 表示要进入哪个pid,1表示整个操作系统的主进程id
-m: 进入mount namespace,挂载点
-u: 进入UTS namespace,也就是上面我们演示的那个namespace
-n: 进入network namespace,网络
-i: 进入IPC namespace,进程间通信
sh: 表示运行/bin/sh

到此为止:docker加上–pid=host加上nsenter,就让我们登录到了在macOS中作为docker容器宿主机的VM里。

方法三

实际上跟方法二一样,但是在方法二中,需要下载至少是alpine镜像这样的最简化Linux操作系统,虽然这个镜像只有5MB多,已经很小了,但是我们还是可以直接下载网络上其它人提供的单独的nsenter镜像,这样的镜像更小,大约只有几百KB。

walkerlee/nsenter镜像有583KB。

docker run --rm -it --privileged --pid=host walkerlee/nsenter -t 1 -m -u -i -n sh

justincormack/nsenter1镜像更小,只有101KB。

docker run -it --rm --privileged --pid=host justincormack/nsenter1