2016年12月31日星期六

Docker_015:ONBUILD 指令用法说明

环境:MAC OS  X 10.12.2 + Docker 1.12.5

1. 父 Dockerfile 定义
FROM ubuntu:16.04
MAINTAINER James Turnbull "james@example.com"
ENV REFRESHED_AT 2013-07-28
RUN apt-get update
RUN apt-get install -y apache2
ENV APACHE_RUN_USER www-data
ENV APACHE_RUN_GROUP www-data
ENV APACHE_LOG_DIR /var/log/apache2
ONBUILD ADD . /var/www/
EXPOSE 80
ENTRYPOINT ["/usr/sbin/apache2"]
CMD ["-D", "FOREGROUND"]

$ docker build -t="jamtur01/apache2" .

2. 子 Dockerfile 定义 
FROM jamtur01/apache2
MAINTAINER James Turnbull "james@example.com"
ENV APPLICATION_NAME webapp
ENV ENVIRONMENT development
 

$ docker build -t="jamtur01/webapp" . 
可以看到,在 FROM 指令之后,Docker 插入了一条 ADD 指令,这条 ADD 指令就是在 ONBUILD 触发器中指定的。
执行完该 ADD 指令后,Docker 才会继续执行构建文件中的后续指令。
这种机制可以将本地源代码添加到镜像。

注意,这种继承关系只能被继承一次,即只能在子镜像中执行,不能在孙子镜像中执行。



2016年12月29日星期四

OpenShift_019:使用 Dockerfile 部署 .war 到 JBoss EAP 7

环境:OCP 3.3

本文利用已有的 JBoss EAP 7 image 作为 base image,编写 Dockerfile 把 .war 文件拷贝到 EAP 部署目录下。

1. mkdir example

2. cd example

3. vim Dockerfile
FROM registry.example.com:5000/jboss-eap-7/eap70-openshift:latest
#EXPOSE 8080 8888
COPY example.war $JBOSS_HOME/standalone/deployments/ROOT.war

4. 复制 example.war 到 example 目录下

5. oc login -u admin -p admin

6. oc new-project example

7. cd .. 退到 example 上一级目录

8. oc new-app example --name=example --insecure-registry=true
输出如下:
--> Found Docker image 07ebd7e (5 months old) from registry.example.com:5000 for "registry.example.com:5000/jboss-eap-7/eap70-openshift:latest"

    JBoss EAP 7.0
    -------------
    Platform for building and running JavaEE applications on JBoss EAP 7.0

    Tags: builder, javaee, eap, eap7

    * An image stream will be created as "eap70-openshift:latest" that will track the source image
    * A Docker build using binary input will be created
      * The resulting image will be pushed to image stream "example:latest"
      * Use 'start-build --from-dir=DIR|--from-repo=DIR|--from-file=FILE' to trigger a new build
      * WARNING: a binary build was created, you must specify one of --from-dir|--from-file|--from-repo when starting builds
    * This image will be deployed in deployment config "example"
    * Ports 8080/tcp, 8443/tcp, 8778/tcp will be load balanced by service "example"
      * Other containers can access this service through the hostname "example"

--> Creating resources with label app=example ...
    imagestream "eap70-openshift" created
    imagestream "example" created
    buildconfig "example" created
    deploymentconfig "example" created
    service "example" created
--> Success
    Use 'oc start-build example' to start a build.
    Run 'oc status' to view your app.

9. oc start-build example --from-dir=example
输出如下:
Uploading directory "example" as binary input for the build ...
build "example-1" started

10. oc get pod
NAME              READY     STATUS    RESTARTS   AGE
example-1-build   1/1       Running   0          1m

11. oc logs example-1-build 
输出如下:
Receiving source from STDIN as archive ...
Step 1 : FROM registry.example.com:5000/jboss-eap-7/eap70-openshift
Trying to pull repository registry.example.com:5000/jboss-eap-7/eap70-openshift ...
Pulling repository registry.example.com:5000/jboss-eap-7/eap70-openshift
Pulling image (latest) from registry.example.com:5000/jboss-eap-7/eap70-openshift
Pulling image (latest) from registry.example.com:5000/jboss-eap-7/eap70-openshift, endpoint: http://registry.example.com:5000/v1/
......
......
Pull complete
Status: Downloaded newer image for registry.example.com:5000/jboss-eap-7/eap70-openshift:latest
registry.example.com:5000/jboss-eap-7/eap70-openshift: this image was pulled from a legacy registry.  Important: This registry version will not be supported in future versions of docker.
 ---> 4cfe6e2044dc
Step 2 : COPY example.war $JBOSS_HOME/standalone/deployments/ROOT.war
 ---> 34fbd02ae32e
Removing intermediate container 635e5c7ec247
Step 3 : ENV "OPENSHIFT_BUILD_NAME" "example-1" "OPENSHIFT_BUILD_NAMESPACE" "example"
 ---> Running in a5dedee83edd
 ---> a8bc2e9b518f
Removing intermediate container a5dedee83edd
Successfully built a8bc2e9b518f

Pushing image 172.30.123.246:5000/example/example:latest ...
Pushed 0/6 layers, 2% complete
Pushed 1/6 layers, 18% complete
Pushed 2/6 layers, 34% complete

12. oc expose service example --hostname=example.apps.example.com

13. 访问 http://example.apps.example.com/index.jsp 


14. 删除 project 中所有对象 oc delete all --all

2016年12月27日星期二

VirtualBox_010:为虚机添加硬盘,并扩展根分区

环境:MAC OS X 10.12.2 (主机)+ RHEL 7.2(客机)




[root@node2 ~]# fdisk -l

磁盘 /dev/sda:8589 MB, 8589934592 字节,16777216 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节
磁盘标签类型:dos
磁盘标识符:0x0006a77f

   设备 Boot      Start         End      Blocks   Id  System
/dev/sda1   *        2048     1026047      512000   83  Linux
/dev/sda2         1026048    16777215     7875584   8e  Linux LVM

磁盘 /dev/sdb:10.7 GB, 10737418240 字节,20971520 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节


磁盘 /dev/mapper/rhel-root:7159 MB, 7159676928 字节,13983744 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节


磁盘 /dev/mapper/rhel-swap:859 MB, 859832320 字节,1679360 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节


磁盘 /dev/mapper/rhel-docker--poolmeta:8 MB, 8388608 字节,16384 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):512 字节 / 512 字节


磁盘 /dev/mapper/docker-253:0-17101729-pool:107.4 GB, 107374182400 字节,209715200 个扇区
Units = 扇区 of 1 * 512 = 512 bytes
扇区大小(逻辑/物理):512 字节 / 512 字节
I/O 大小(最小/最佳):65536 字节 / 65536 字节

[root@node2 ~]# df -Th
文件系统              类型      容量  已用  可用 已用% 挂载点
/dev/mapper/rhel-root xfs       6.7G  3.9G  2.9G   58% /
devtmpfs              devtmpfs  1.9G     0  1.9G    0% /dev
tmpfs                 tmpfs     1.9G     0  1.9G    0% /dev/shm
tmpfs                 tmpfs     1.9G  8.4M  1.9G    1% /run
tmpfs                 tmpfs     1.9G     0  1.9G    0% /sys/fs/cgroup
/dev/sda1             xfs       497M  166M  331M   34% /boot
tmpfs                 tmpfs     380M     0  380M    0% /run/user/0

[root@node2 ~]# fdisk /dev/sdb
n
p
1
回车
回车
w

[root@node2 ~]# partprobe

[root@node2 ~]# pvcreate /dev/sdb1

[root@node2 ~]# vgs
  VG   #PV #LV #SN Attr   VSize VFree
  rhel   1   3   0 wz--n- 7.51g 32.00m

[root@node2 ~]# vgextend rhel /dev/sdb1

[root@node2 ~]# vgs
  VG   #PV #LV #SN Attr   VSize  VFree
  rhel   2   3   0 wz--n- 17.50g 10.03g

[root@node2 ~]# lvextend -L +10G /dev/rhel/root
  Size of logical volume rhel/root changed from 6.67 GiB (1707 extents) to 16.67 GiB (4267 extents).
   Logical volume root successfully resized.

[root@node2 ~]# xfs_growfs /
meta-data=/dev/mapper/rhel-root  isize=256    agcount=4, agsize=436992 blks
         =                       sectsz=512   attr=2, projid32bit=1
         =                       crc=0        finobt=0
data     =                       bsize=4096   blocks=1747968, imaxpct=25
         =                       sunit=0      swidth=0 blks
naming   =version 2              bsize=4096   ascii-ci=0 ftype=0
log      =internal               bsize=4096   blocks=2560, version=2
         =                       sectsz=512   sunit=0 blks, lazy-count=1
realtime =none                   extsz=4096   blocks=0, rtextents=0
data blocks changed from 1747968 to 4369408

[root@node2 ~]# df -Th
文件系统              类型      容量  已用  可用 已用% 挂载点
/dev/mapper/rhel-root xfs        17G  3.9G   13G   23% /
devtmpfs              devtmpfs  1.9G     0  1.9G    0% /dev
tmpfs                 tmpfs     1.9G     0  1.9G    0% /dev/shm
tmpfs                 tmpfs     1.9G  8.4M  1.9G    1% /run
tmpfs                 tmpfs     1.9G     0  1.9G    0% /sys/fs/cgroup
/dev/sda1             xfs       497M  166M  331M   34% /boot
tmpfs                 tmpfs     380M     0  380M    0% /run/user/0

 

2016年12月20日星期二

OpenShift_018:如何重头定制一个 builder image?

环境:OSE 3.0.1

本文介绍如何重头做一个 builder image,当然这个重头也不是完全重头开始,至少你要有一个 linux image,该 linux image 一般官网都会提供。
比如 cenos7 image 在 https://hub.docker.com;rhel7 image 在 http://registry.access.redhat.com (需要有红帽订阅)。
另外,在 https://github.com/openshift/sti-base 提供了一些 OpenShift base image。

第1步,根据 rhel7 image 制作一个 base-rhel7 image。base-rhel7 image 将作为 OpenShift 3 中所有 builder image 的 base image。

第2步,根据 base-rhel7 image 制作一个 apache httpd-s2i builder image。httpd-s2i builder image 将用于发布和运行静态 html 页面。

1. 制作 base-rhel7 image
(1)git 克隆 sti-base,感觉这个和 https://github.com/openshift/sti-base 是一个项目
[student@workstation ~]$ git clone http://workstation.pod0.example.com/sti-base.git
(2)下载 rhel7 image
[student@workstation ~]$ sudo docker pull workstation.pod0.example.com:5000/rhel7
(3)build base-rhel7 image

[student@workstation ~]$ cd sti-base
[student@workstation sti-base]$ sudo docker build -t openshift/base-rhel7 -f Dockerfile.rhel7 .
Dockerfile.rhel7 内容如下:
FROM rhel7
#FROM workstation.pod0.example.com:5000/rhel7

# This image is the base image for all OpenShift v3 language Docker images.
# Location of the STI scripts inside the image
LABEL io.openshift.s2i.scripts-url=image:///usr/local/sti

# DEPRECATED: This label will be kept here for backward compatibility
LABEL io.s2i.scripts-url=image:///usr/local/sti

# Deprecated. Use above LABEL instead, because this will be removed in future versions.
ENV STI_SCRIPTS_URL=image:///usr/local/sti

# Labels consumed by Red Hat build service
LABEL BZComponent="openshift-sti-base-docker" \
      Name="openshift3/sti-base" \
      Version="1.0" \
      Release="1" \
      Architecture="x86_64"

# The $HOME is not set by default, but some applications needs this variable
# TODO: There is a bug in rhel7.1 image where the PATH variable is not exported
# properly as Docker image metadata, which causes the $PATH variable do not
# expand properly.
ENV HOME=/opt/app-root/src \
    PATH=/opt/app-root/src/bin:/opt/app-root/bin:/usr/local/sti:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# When bash is started non-interactively, to run a shell script, for example it
# looks for this variable and source the content of this file. This will enable
# the SCL for all scripts without need to do 'scl enable'.
ADD contrib/scl_enable /opt/app-root/etc/scl_enable
ENV BASH_ENV=/opt/app-root/etc/scl_enable \
    ENV=/opt/app-root/etc/scl_enable \
    PROMPT_COMMAND=". /opt/app-root/etc/scl_enable"

# This is the list of basic dependencies that all language Docker image can
# consume.
# Also setup the 'openshift' user that is used for the build execution and for the
# application runtime execution.
# TODO: Use better UID and GID values
#RUN yum-config-manager --enable rhel-7-server-optional-rpms && \
ADD training.repo /etc/yum.repos.d/training.repo
RUN yum install -y --setopt=tsflags=nodocs --skip-broken \
  autoconf \
  automake \
  bsdtar \
  findutils \
  gcc-c++ \
  gdb \
  gettext \
  git \
  libcurl-devel \
  libxml2-devel \
  libxslt-devel \
  lsof \
  make \
  mariadb-devel \
  mariadb-libs \
  openssl-devel \
  patch \
  postgresql-devel \
  procps-ng \
  scl-utils \
  sqlite-devel \
  tar \
  unzip \
  wget \
  which \
  yum-utils \
  zlib-devel && \
  yum clean all -y && \
  mkdir -p ${HOME} && \
  useradd -u 1001 -r -g 0 -d ${HOME} -s /sbin/nologin \
      -c "Default Application User" default && \
  chown -R 1001:0 /opt/app-root

# Create directory where the image STI scripts will be located
# Install the base-usage script with base image usage informations
ADD bin/base-usage /usr/local/sti/base-usage

# Use entrypoint so path is correctly adjusted already at the time the command
# is searching, so something like docker run IMG python runs binary from SCL
ADD bin/container-entrypoint /usr/bin/container-entrypoint

# Directory with the sources is set as the working directory so all STI scripts
# can execute relative to this path
WORKDIR ${HOME}

ENTRYPOINT ["container-entrypoint"]
CMD ["base-usage"]

2. 制作 httpd-s2i builder image
(1)安装 s2i 工具
s2i 工具不在 RHEL7 或 OpenShift 3 安装包中,需要单独安装。
[student@workstation ~]$ s2i version
(2)创建 httpd-s2i 项目
[student@workstation ~]$ s2i create httpd-s2i httpd-s2i
第 1 个 httpd-s2i 是 image 的名称, 第 2 个 httpd-s2i 是 project 的名称。
该命令执行后,会生成一个目录框架,其中包括 Dokerfile 以及 .sti/bin/run, .sti/bin/assemble 等文件。
你可以在此基础上,再做修改。
(3)添加必要的文件及相关内容
[student@workstation ~]$ cd httpd-s2i
  •  httpd-s2i/Dockerfile 内容如下:
FROM openshift/base-rhel7

EXPOSE 8080

# Install Apache httpd from the Red Hat SCL
#RUN yum-config-manager --enable rhel-7-server-optional-rpms && \
ADD training.repo /etc/yum.repos.d/training.repo
RUN yum install -y --setopt=tsflags=nodocs httpd24-httpd && \
    yum clean all -y

LABEL io.k8s.description="Platform for building and running httpd applications" \
      io.k8s.display-name="Apache 2.4" \
      io.openshift.expose-services="8080:http" \
      io.openshift.tags="builder,httpd"

# Copy the S2I scripts from the specific language image to /usr/local/sti
COPY ./.s2i/bin/ /usr/local/sti

# Each language image can have 'contrib' a directory with extra files needed to
# run and build the applications.
COPY ./contrib/ /opt/app-root

# In order to drop the root user, we have to make some directories world
# writeable as OpenShift default security model is to run the container under
# random UID.
RUN sed -i -f /opt/app-root/etc/httpdconf.sed /opt/rh/httpd24/root/etc/httpd/conf/httpd.conf && \
    head -n151 /opt/rh/httpd24/root/etc/httpd/conf/httpd.conf | tail -n1 | grep "AllowOverride All" || exit && \
    chmod -R a+rwx /opt/rh/httpd24/root/var/run/httpd && \
    chown -R 1001:1001 /opt/app-root

USER 1001

# Set the default CMD to print the usage of the language image
CMD ["usage"]
  •    httpd-s2i/training.repo 内容如下:
[rhel-7-server-rpms]
name=Rhel 7 rpms
baseurl=http://content.example.com/ose3.0/x86_64/dvd/rhel-7-server-rpms
enabled=1
gpgcheck=0

[rhel-7-server-extras-rpms]
name=Rhel 7 extras
baseurl=http://content.example.com/ose3.0/x86_64/dvd/rhel-7-server-extras-rpms
enabled=1
gpgcheck=0

[rhel-7-server-optional-rpms]
name=Rhel 7 optional
baseurl=http://content.example.com/ose3.0/x86_64/dvd/rhel-7-server-optional-rpms
enabled=1
gpgcheck=0

[rhel-7-server-ose-3.0-rpms]
name=OpenShift
baseurl=http://content.example.com/ose3.0/x86_64/dvd/rhel-7-server-ose-3.0-rpms
enabled=1
gpgcheck=0

[rhel-server-rhscl-7-rpms]
name=Software Collections
baseurl=http://content.example.com/ose3.0/x86_64/rhscl/rhel-server-rhscl-7-rpms
enabled=1
gpgcheck=0
  •  httpd-s2i/contrib/etc/scl_enable 内容如下:
# IMPORTANT: Do not add more content to this file unless you know what you are
#            doing. This file is sourced everytime the shell session is opened.
#
# This will make scl collection binaries work out of box.
unset BASH_ENV PROMPT_COMMAND ENV
source scl_source enable httpd24
  •   httpd-s2i/contrib/etc/httpdconf.sed 内容如下:
s/^Listen 80/Listen 0.0.0.0:8080/
s/^User apache/User default/
s/^Group apache/Group root/
s%^DocumentRoot "/opt/rh/httpd24/root/var/www/html"%DocumentRoot "/opt/app-root/src"%
s%^s%^s%^ErrorLog "logs/error_log"%ErrorLog "/tmp/error_log"%
s%CustomLog "logs/access_log"%CustomLog "/tmp/access_log"%
151s%AllowOverride None%AllowOverride All%

  •   httpd-s2i/.sti/bin/assemble 内容如下:
#!/bin/bash -e
#
# S2I assemble script for the 'httpd-s2i' image.
# The 'assemble' script builds your application source ready to run.
#
# For more information refer to the documentation:
#    https://github.com/openshift/source-to-image/blob/master/docs/builder_image.md
#

if [ "$1" = "-h" ]; then
    # If the 'httpd-s2i' assemble script is executed with '-h' flag,
    # print the usage.
    exec /usr/local/s2i/usage
fi

# Restore artifacts from the previous build (if they exist).
#
if [ "$(ls /tmp/artifacts/ 2>/dev/null)" ]; then
  echo "---> Restoring build artifacts"
  mv /tmp/artifacts/. ./
fi

echo "---> Installing application source"
cp -Rf /tmp/src/. ./

echo "---> Building application from source"
# TODO: Add build steps for your application, eg npm install, bundle install
  •   httpd-s2i/.sti/bin/run 内容如下:
#!/bin/bash -e
#
# S2I run script for the 'httpd-sti' image.
# The run script executes the server that runs your application.
#
# For more information see the documentation:
#    https://github.com/openshift/source-to-image/blob/master/docs/builder_image.md
#

exec httpd -D FOREGROUND
  •   httpd-s2i/test/test-app/index.html 内容如下:
<html>
<head>
   <title>HTML Home Page</title>
</head>
<body>
<h1>This is the home page</h1>
</body>
</html>

(4)build httpd-s2i image
[student@workstation httpd-s2i]$ sudo docker build -t httpd-s2i .

(5)测试 httpd-s2i image
[student@workstation httpd-s2i]$ cd test/test-app
[student@workstation test-app]$ git init .
[student@workstation test-app]$ git add .
[student@workstation test-app]$ git commit -m "test HTML application"

[student@workstation httpd-s2i]$ sudo s2i build file:///home/student/httpd-s2i/test/test-app/ httpd-s2i:latest httpd-s2i-test
httpd-s2i:latest 是 builder image; httpd-s2i-test 是要生成的应用 image;file:///home/student/httpd-s2i/test/test-app/ 是源代码根目录。

[student@workstation httpd-s2i]$ sudo docker run -p 8080:8080 httpd-s2i-test

新开一个终端,访问
[student@workstation ~]$ curl http://127.0.0.1:8080

(6)导出 httpd-s2i image
[student@workstation ~]$ sudo docker save -o httpd-s2i.tar httpd-s2i
[student@workstation ~]$ gzip -v httpd-s2i.tar

至此,终于得到了  httpd-s2i.tar.gz,现在你可以把它发布了。
如何发布定制的 builder image,请参考《 OpenShift_016:如何发布定制的 builder image ?

2016年12月19日星期一

OpenShift_017:如何定制 build 的过程?

环境:OSE 3.0.1

OpenShift 3 使用 s2i 工具把源代码 build 成 image。
在构建过程中,如果想要加入自己的一些操作怎么办?
s2i 允许你添加一些脚本,脚本可以使用任何语言编写,只要在 builder image 中可以执行。

脚本默认位置在源代码根目录下的 .sti/bin 目录下。也可以由 --scipts-url 参数指定。
脚本一共有 5 个:
(1)assemble 编译源代码,并放到适当的目录。必选。
(2)run 执行应用。必选。
(3)save-artifacts 收集所有依赖包,加速构建过程。可选。
(4)usegage 使用说明。 可选。
(5)test/run 测试 image 是否工作正常。 可选。

下面定制一个 php 的 build 过程。

[student@workstation ~]$ git clone http://workstation.pod0.example.com/php-custom
[student@workstation php-custom]$ cd php-custom
[student@workstation php-custom]$ mkdir -p .sti/bin
[student@workstation php-custom]$ cp assemble .sti/bin
修改 assemble,修改后的完整内容如下:
#!/bin/bash
set -e
echo "---> Installing application source..."
cp -Rf /tmp/src/. ./

#add code here
DATE=`date`
echo "---> Creating the built html file"
echo "Built date: $DATE" > ./built.html

if [ -f composer.json ]; then
        echo "Found 'composer.json', installing dependencies using composer.phar... "
        # Install Composer
        php -r "readfile('https://getcomposer.org/installer');" | php
        # Install App dependencies using Composer
        ./composer.phar install --no-interaction --no-ansi --no-scripts --optimize-autoloader
        if [ ! -f composer.lock ]; then
                echo -e "\nConsider adding a 'composer.lock' file into your source repository.\n"
        fi
fi

[student@workstation php-custom]$ git add .
[student@workstation php-custom]$ git commit -m "Added custom assemble process"
[student@workstation php-custom]$ git push
[student@workstation php-custom]$ cd

[student@workstation ~]$ oc login -u developer -p openshift
[student@workstation ~]$ oc new-project php-custom
[student@workstation ~]$ oc new-app http://workstation.pod0.example.com/php-custom
[student@workstation ~]$ oc build-logs php-custom-1
......
I1218 23:37:53.795201       1 docker.go:400] Attaching to container
I1218 23:37:53.798921       1 docker.go:457] Starting container
I1218 23:37:54.002178       1 docker.go:467] Waiting for container
I1218 23:37:54.052017       1 sti.go:393] ---> Installing application source...
I1218 23:37:54.062962       1 sti.go:393] ---> Creating the built html file
I1218 23:37:54.327394       1 docker.go:473] Container exited
I1218 23:37:54.327414       1 docker.go:479] Invoking postExecution function
I1218 23:37:54.327433       1 sti.go:220] No .sti/environment provided (no environment file found in application sources)
......

可以看到打出了 ---> Creating the built html file 这一行内容。

OpenShift_016:如何发布定制的 builder image ?

环境:OSE 3.0.1

假设你已经有了一个定制的 go builder image,怎么把它发布到 OpenShift 上,让别人可以使用呢?

1. 把 tar 文件导入为镜像
[student@workstation ~]$ sudo docker load -i customizing-go/go-rhel7.tar.gz
[student@workstation ~]$ sudo docker images | grep go-rhel7
openshift3/go-rhel7   v1.0                4834dc05f775        14 months ago       502.9 MB

2. 把 image 打上 tag,并放入私有仓库
[student@workstation ~]$ sudo docker tag openshift3/go-rhel7:v1.0 workstation.pod0.example.com:5000/openshift3/go-rhel7:v1.0
[student@workstation ~]$ sudo docker push workstation.pod0.example.com:5000/openshift3/go-rhel7:v1.0

3. 创建 image stream
[root@master ~]# oc login -u system:admin
[root@master ~]# oc create -f go-is.json -n openshift
go-is.json 内容如下:
{

    "kind":"ImageStream",
    "apiVersion":"v1",
    "metadata":{
        "name":"go",
        "creationTimestamp":null,
        "annotations":{
            "openshift.io/image.dockerRepositoryCheck":"2015-08-24T15:16:26Z"
        }
    },
    "spec":{
        "dockerImageRepository":"workstation.pod0.example.com:5000/openshift3/go-rhel7",
        "tags":[
            {
                "name":"v1.0"
            }
        ]
    },
    "status":{
        "dockerImageRepository":""
    }

}

[root@master ~]# oc get is -n openshift | grep go-thel7
输出如下:
go                                   workstation.pod0.example.com:5000/openshift3/go-rhel7
 
发现 TAGS 一栏是空的,需要把 image 的 tag 导入到 image stream 中。
[root@master ~]# oc import-image go -n openshift
输出如下:
Waiting for the import to complete, CTRL+C to stop waiting.
The import completed successfully.

Name:            go
Created:        17 seconds ago
Labels:           
Annotations:        openshift.io/image.dockerRepositoryCheck=2016-12-19T03:22:59Z
Docker Pull Spec:    workstation.pod0.example.com:5000/openshift3/go-rhel7

Tag    Spec    Created            PullSpec                            Image
v1.0        Less than a second ago    workstation.pod0.example.com:5000/openshift3/go-rhel7:v1.0    4834dc05f7753ee9df37b6e7b78ca6b12b0e88cb0b12e36f23e560211ce35cc5


[root@master ~]# oc get is -n openshift | grep go-thel7
输出如下:
go                                   workstation.pod0.example.com:5000/openshift3/go-rhel7  v1.0
这次 TAGS 栏有了版本号。

4. 为新的 builder image 创建新的 template,这样让用户使用起来更方便
[root@master ~]# oc create -f go-template.json -n openshift
go-template.json 内容如下:

{
    "kind": "Template",
    "apiVersion": "v1",
    "metadata": {
        "name": "go-sti",
        "creationTimestamp": null
    },
    "objects": [
        {
            "apiVersion": "v1",
            "kind": "Service",
            "metadata": {
                "annotations": {
                    "description": "The web server's http port."
                },
                "labels": {
                    "application": "${APPLICATION_NAME}"
                },
                "name": "${APPLICATION_NAME}"
            },
            "spec": {
                "ports": [
                    {
                        "port": 8080,
                        "targetPort": 8080
                    }
                ],
                "selector": {
                    "deploymentConfig": "${APPLICATION_NAME}"
                }
            }
        },
        {
            "apiVersion": "v1",
            "id": "${APPLICATION_NAME}-http-route",
            "kind": "Route",
            "metadata": {
                "annotations": {
                    "description": "Route for application's http service."
                },
                "labels": {
                    "application": "${APPLICATION_NAME}"
                },
                "name": "${APPLICATION_NAME}-http-route"
            },
            "spec": {
                "host": "${APPLICATION_HOSTNAME}",
                "to": {
                    "name": "${APPLICATION_NAME}"
                }
            }
        },
        {
            "apiVersion": "v1",
            "kind": "ImageStream",
            "metadata": {
                "labels": {
                    "application": "${APPLICATION_NAME}"
                },
                "name": "${APPLICATION_NAME}"
            }
        },
        {
            "apiVersion": "v1",
            "kind": "BuildConfig",
            "metadata": {
                "labels": {
                    "application": "${APPLICATION_NAME}"
                },
                "name": "${APPLICATION_NAME}"
            },
            "spec": {
                "env": [
                    {
                        "name": "GO_MAIN",
                        "value": "${GO_MAIN}"
                    },
                    {
                        "name": "DOUGLAS",
                        "value": "${DOUGLAS}"
                    }
                ],
                "output": {
                    "to": {
                        "name": "${APPLICATION_NAME}"
                    }
                },
                "source": {
                    "contextDir": "${GIT_CONTEXT_DIR}",
                    "git": {
                        "ref": "${GIT_REF}",
                        "uri": "${GIT_URI}"
                    },
                    "type": "Git"
                },
                "strategy": {
                    "sourceStrategy": {
                        "from": {
                            "kind": "ImageStreamTag",
                            "name": "go:v1.0",
                            "namespace": "openshift"
                        }
                    },
                    "type": "Source"
                },
                "triggers": [
                    {
                        "github": {
                            "secret": "${GITHUB_TRIGGER_SECRET}"
                        },
                        "type": "github"
                    },
                    {
                        "generic": {
                            "secret": "${GENERIC_TRIGGER_SECRET}"
                        },
                        "type": "generic"
                    },
                    {
                        "imageChange": {},
                        "type": "imageChange"
                    }
                ]
            }
        },
        {
            "apiVersion": "v1",
            "kind": "DeploymentConfig",
            "metadata": {
                "labels": {
                    "application": "${APPLICATION_NAME}"
                },
                "name": "${APPLICATION_NAME}"
            },
            "spec": {
                "replicas": 1,
                "selector": {
                    "deploymentConfig": "${APPLICATION_NAME}"
                },
                "strategy": {
                    "type": "Recreate"
                },
                "template": {
                    "metadata": {
                        "labels": {
                            "application": "${APPLICATION_NAME}",
                            "deploymentConfig": "${APPLICATION_NAME}"
                        },
                        "name": "${APPLICATION_NAME}"
                    },
                    "spec": {
                        "containers": [
                            {
                                "env": [],
                                "image": "${APPLICATION_NAME}",
                                "imagePullPolicy": "Always",
                                "name": "${APPLICATION_NAME}",
                                "ports": [
                                    {
                                        "containerPort": 8080
                                    }
                                ]
                            }
                        ]
                    }
                },
                "triggers": [
                    {
                        "imageChangeParams": {
                            "automatic": true,
                            "containerNames": [
                                "${APPLICATION_NAME}"
                            ],
                            "from": {
                                "kind": "ImageStream",
                                "name": "${APPLICATION_NAME}"
                            }
                        },
                        "type": "ImageChange"
                    }
                ]
            }
        }
    ],
    "parameters": [
        {
            "name": "APPLICATION_NAME",
            "description": "Application NAME"
        },
        {
            "name": "GIT_URI",
            "description": "GIT URI"
        },
        {
            "name": "GIT_REF",
            "description": "Git branch"
        },
        {
            "name": "GO_MAIN",
            "description": "Main GO package"
        },
        {
            "name": "GIT_CONTEXT_DIR",
            "description": "Path within Git project to build; empty for root project directory."
        },
        {
            "name": "GITHUB_TRIGGER_SECRET",
            "description": "Github trigger secret",
            "generate": "expression",
            "from": "[a-zA-Z0-9]{8}"
        },
        {
            "name": "GENERIC_TRIGGER_SECRET",
            "description": "Generic build trigger secret",
            "generate": "expression",
            "from": "[a-zA-Z0-9]{8}"
        },
        {
            "name": "APPLICATION_HOSTNAME",
            "description": "Application hostname"
        }
    ],
    "labels": {
        "template": "go-sti"
    }
}

5. 创建一个 project 使用该 template
[student@workstation ~]$ oc login -u student -p redhat

[student@workstation ~]$ oc new-project go

在控制台,点击 show all templates,找到 go-sti,并点击,输入如下参数:

点击 Create,剩下的就是等待 build 和 deploy 啦。

2016年12月17日星期六

OpenShift_015:使用 Template 创建一个复杂应用(Java + MySQL)

环境:OSE 3.0.1

本文我们创建一个复杂一些的应用,Java + MySQL。
在上一篇文章我们已经了解了如何一步步创建需要的对象,了解了 OpenShift 构建应用的整个过程。
现在我们使用 Template 创建一个复杂应用。

1. 为 MySQL 配置 NFS
[root@master ~]# mkdir /var/export/membermysql
[root@master ~]# chown nfsnobody:nfsnobody /var/export/membermysql
[root@master ~]# chmod 700 /var/export/membermysql

[root@master ~]# vim /etc/exports
/var/export/membermysql *(rw,async,all_squash)

[root@master ~]# exportfs -a

2. 创建 PV
[root@master ~]# oc login -u system:admin

[root@master ~]# oc create -f mysqlPV.json
mysqlPV.json 内容如下:
{
  "apiVersion": "v1",
  "kind": "PersistentVolume",
  "metadata": {
    "name": "mysqldb-member-volume"
  },
  "spec": {
    "capacity": {
        "storage": "1Gi"
    },
    "accessModes": [ "ReadWriteOnce" ],
    "nfs": {
        "path": "/var/export/membermysql",
        "server": "master.pod0.example.com"
    },
    "persistentVolumeReclaimPolicy": "Recycle"
  }
}

3. 创建 project
[student@workstation ~]$ oc login -u devloper -p openshift
 
[student@workstation ~]$ oc new-project member

4. 创建 secret
[student@workstation ~]$ oc create -f secret.json
serviceaccounts/eap-service-account
secrets/eap-app-secret-member
secret.json 内容如下:
{
      "kind": "List",
      "apiVersion": "v1",
      "metadata": {},
      "items": [
          {
              "kind": "ServiceAccount",
              "apiVersion": "v1",
              "metadata": {
                  "name": "eap-service-account"
              },
              "secrets": [
                  {
                      "name": "eap-app-secret-member"
                  }
              ]
          },
          {
              "kind": "Secret",
              "apiVersion": "v1",
              "metadata": {
                  "annotations": {
                      "description": "Default secret file with name 'jboss' and password 'mykeystorepass'"
                  },
                  "name": "eap-app-secret-member"
              },
              "data": {
                  "keystore.jks": "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"
              }
          }
      ]
}

以上这些步骤还需要手动去做,下面就开始根据 Template 创建其它所有资源。

5. 导出指定的 Template 定义
(1)查看[student@workstation ~]$ oc get templates -n openshift

(2)查看 eap6-mysql-persistent-sti template 的参数定义
[student@workstation ~]$ oc process --parameters eap6-mysql-persistent-sti -n openshift
(3)导出 template 定义

[student@workstation ~]$ oc -o json export template eap6-mysql-persistent-sti -n openshift > eap6-mysql-persistent-sti.json
 (4)导出 template 定义
oc process -f \
eap6-mysql-persistent-sti.json -v \
APPLICATION_NAME=member,\
APPLICATION_HOSTNAME=member.cloudapps0.example.com,\
GIT_URI=http://workstation.pod0.example.com/member,\
DB_JNDI=java:jboss/datasources/memberDS,\
DB_DATABASE=member,\
EAP_HTTPS_SECRET=eap-app-secret-member,\
EAP_HTTPS_KEYSTORE=keystore.jks,\
EAP_HTTPS_NAME=jboss,\
EAP_HTTPS_PASSWORD=mykeystorepass,\
DB_USERNAME=member,\
DB_PASSWORD=member > processedtemplate.json

processedtemplate.json 内容如下:
{
    "kind": "List",
    "apiVersion": "v1beta3",
    "metadata": {},
    "items": [
        {
            "apiVersion": "v1",
            "kind": "Service",
            "metadata": {
                "annotations": {
                    "description": "The web server's http port."
                },
                "labels": {
                    "application": "member",
                    "template": "eap6-mysql-persistent-sti"
                },
                "name": "member"
            },
            "spec": {
                "ports": [
                    {
                        "port": 8080,
                        "targetPort": 8080
                    }
                ],
                "selector": {
                    "deploymentConfig": "member"
                }
            }
        },
        {
            "apiVersion": "v1",
            "kind": "Service",
            "metadata": {
                "annotations": {
                    "description": "The web server's https port."
                },
                "labels": {
                    "application": "member",
                    "template": "eap6-mysql-persistent-sti"
                },
                "name": "secure-member"
            },
            "spec": {
                "ports": [
                    {
                        "port": 8443,
                        "targetPort": 8443
                    }
                ],
                "selector": {
                    "deploymentConfig": "member"
                }
            }
        },
        {
            "apiVersion": "v1",
            "kind": "Service",
            "metadata": {
                "annotations": {
                    "description": "Ping service for clustered applications."
                },
                "labels": {
                    "application": "member",
                    "template": "eap6-mysql-persistent-sti"
                },
                "name": "member-ping"
            },
            "spec": {
                "portalIP": "None",
                "ports": [
                    {
                        "port": 8888,
                        "targetPort": 8888
                    }
                ],
                "selector": {
                    "deploymentConfig": "member"
                }
            }
        },
        {
            "apiVersion": "v1",
            "kind": "Service",
            "metadata": {
                "annotations": {
                    "description": "The database server's port."
                },
                "labels": {
                    "application": "member",
                    "template": "eap6-mysql-persistent-sti"
                },
                "name": "member-mysql"
            },
            "spec": {
                "ports": [
                    {
                        "port": 3306,
                        "targetPort": 3306
                    }
                ],
                "selector": {
                    "deploymentConfig": "member-mysql"
                }
            }
        },
        {
            "apiVersion": "v1",
            "id": "member-http-route",
            "kind": "Route",
            "metadata": {
                "annotations": {
                    "description": "Route for application's http service."
                },
                "labels": {
                    "application": "member",
                    "template": "eap6-mysql-persistent-sti"
                },
                "name": "member-http-route"
            },
            "spec": {
                "host": "member.cloudapps0.example.com",
                "to": {
                    "name": "member"
                }
            }
        },
        {
            "apiVersion": "v1",
            "id": "member-https-route",
            "kind": "Route",
            "metadata": {
                "annotations": {
                    "description": "Route for application's https service."
                },
                "labels": {
                    "application": "member",
                    "template": "eap6-mysql-persistent-sti"
                },
                "name": "member-https-route"
            },
            "spec": {
                "host": "member.cloudapps0.example.com",
                "tls": {
                    "termination": "passthrough"
                },
                "to": {
                    "name": "secure-member"
                }
            }
        },
        {
            "apiVersion": "v1",
            "kind": "ImageStream",
            "metadata": {
                "labels": {
                    "application": "member",
                    "template": "eap6-mysql-persistent-sti"
                },
                "name": "member"
            }
        },
        {
            "apiVersion": "v1",
            "kind": "BuildConfig",
            "metadata": {
                "labels": {
                    "application": "member",
                    "template": "eap6-mysql-persistent-sti"
                },
                "name": "member"
            },
            "spec": {
                "output": {
                    "to": {
                        "kind": "ImageStreamTag",
                        "name": "member:latest"
                    }
                },
                "source": {
                    "contextDir": "",
                    "git": {
                        "ref": "master",
                        "uri": "http://workstation.pod0.example.com/member"
                    },
                    "type": "Git"
                },
                "strategy": {
                    "sourceStrategy": {
                        "from": {
                            "kind": "ImageStreamTag",
                            "name": "jboss-eap6-openshift:6.4",
                            "namespace": "openshift"
                        }
                    },
                    "type": "Source"
                },
                "triggers": [
                    {
                        "github": {
                            "secret": "qj8gkw0O"
                        },
                        "type": "GitHub"
                    },
                    {
                        "generic": {
                            "secret": "JIeMaJxi"
                        },
                        "type": "Generic"
                    },
                    {
                        "imageChange": {},
                        "type": "ImageChange"
                    }
                ]
            }
        },
        {
            "apiVersion": "v1",
            "kind": "DeploymentConfig",
            "metadata": {
                "labels": {
                    "application": "member",
                    "template": "eap6-mysql-persistent-sti"
                },
                "name": "member"
            },
            "spec": {
                "replicas": 1,
                "selector": {
                    "deploymentConfig": "member"
                },
                "strategy": {
                    "type": "Recreate"
                },
                "template": {
                    "metadata": {
                        "labels": {
                            "application": "member",
                            "deploymentConfig": "member"
                        },
                        "name": "member"
                    },
                    "spec": {
                        "containers": [
                            {
                                "env": [
                                    {
                                        "name": "DB_SERVICE_PREFIX_MAPPING",
                                        "value": "member-mysql=DB"
                                    },
                                    {
                                        "name": "DB_JNDI",
                                        "value": "java:jboss/datasources/memberDS"
                                    },
                                    {
                                        "name": "DB_USERNAME",
                                        "value": "member"
                                    },
                                    {
                                        "name": "DB_PASSWORD",
                                        "value": "member"
                                    },
                                    {
                                        "name": "DB_DATABASE",
                                        "value": "member"
                                    },
                                    {
                                        "name": "TX_DATABASE_PREFIX_MAPPING",
                                        "value": "member-mysql=DB"
                                    },
                                    {
                                        "name": "DB_MIN_POOL_SIZE",
                                        "value": ""
                                    },
                                    {
                                        "name": "DB_MAX_POOL_SIZE",
                                        "value": ""
                                    },
                                    {
                                        "name": "DB_TX_ISOLATION",
                                        "value": ""
                                    },
                                    {
                                        "name": "OPENSHIFT_DNS_PING_SERVICE_NAME",
                                        "value": "member-ping"
                                    },
                                    {
                                        "name": "OPENSHIFT_DNS_PING_SERVICE_PORT",
                                        "value": "8888"
                                    },
                                    {
                                        "name": "EAP_HTTPS_KEYSTORE_DIR",
                                        "value": "/etc/eap-secret-volume"
                                    },
                                    {
                                        "name": "EAP_HTTPS_KEYSTORE",
                                        "value": "keystore.jks"
                                    },
                                    {
                                        "name": "EAP_HTTPS_NAME",
                                        "value": "jboss"
                                    },
                                    {
                                        "name": "EAP_HTTPS_PASSWORD",
                                        "value": "mykeystorepass"
                                    },
                                    {
                                        "name": "HORNETQ_CLUSTER_PASSWORD",
                                        "value": "gAqelq4m"
                                    },
                                    {
                                        "name": "HORNETQ_QUEUES",
                                        "value": ""
                                    },
                                    {
                                        "name": "HORNETQ_TOPICS",
                                        "value": ""
                                    }
                                ],
                                "image": "member",
                                "imagePullPolicy": "Always",
                                "name": "member",
                                "ports": [
                                    {
                                        "containerPort": 8080,
                                        "name": "http",
                                        "protocol": "TCP"
                                    },
                                    {
                                        "containerPort": 8443,
                                        "name": "https",
                                        "protocol": "TCP"
                                    },
                                    {
                                        "containerPort": 8888,
                                        "name": "ping",
                                        "protocol": "TCP"
                                    }
                                ],
                                "readinessProbe": {
                                    "exec": {
                                        "command": [
                                            "/bin/bash",
                                            "-c",
                                            "/opt/eap/bin/readinessProbe.sh"
                                        ]
                                    }
                                },
                                "volumeMounts": [
                                    {
                                        "mountPath": "/etc/eap-secret-volume",
                                        "name": "eap-keystore-volume",
                                        "readOnly": true
                                    }
                                ]
                            }
                        ],
                        "serviceAccount": "eap-service-account",
                        "volumes": [
                            {
                                "name": "eap-keystore-volume",
                                "secret": {
                                    "secretName": "eap-app-secret-member"
                                }
                            }
                        ]
                    }
                },
                "triggers": [
                    {
                        "imageChangeParams": {
                            "automatic": true,
                            "containerNames": [
                                "member"
                            ],
                            "from": {
                                "kind": "ImageStream",
                                "name": "member"
                            }
                        },
                        "type": "ImageChange"
                    }
                ]
            }
        },
        {
            "apiVersion": "v1",
            "kind": "DeploymentConfig",
            "metadata": {
                "labels": {
                    "application": "member",
                    "template": "eap6-mysql-persistent-sti"
                },
                "name": "member-mysql"
            },
            "spec": {
                "replicas": 1,
                "selector": {
                    "deploymentConfig": "member-mysql"
                },
                "strategy": {
                    "type": "Recreate"
                },
                "template": {
                    "metadata": {
                        "labels": {
                            "application": "member",
                            "deploymentConfig": "member-mysql"
                        },
                        "name": "member-mysql"
                    },
                    "spec": {
                        "containers": [
                            {
                                "env": [
                                    {
                                        "name": "MYSQL_USER",
                                        "value": "member"
                                    },
                                    {
                                        "name": "MYSQL_PASSWORD",
                                        "value": "member"
                                    },
                                    {
                                        "name": "MYSQL_DATABASE",
                                        "value": "member"
                                    },
                                    {
                                        "name": "MYSQL_LOWER_CASE_TABLE_NAMES",
                                        "value": ""
                                    },
                                    {
                                        "name": "MYSQL_MAX_CONNECTIONS",
                                        "value": ""
                                    },
                                    {
                                        "name": "MYSQL_FT_MIN_WORD_LEN",
                                        "value": ""
                                    },
                                    {
                                        "name": "MYSQL_FT_MAX_WORD_LEN",
                                        "value": ""
                                    },
                                    {
                                        "name": "MYSQL_AIO",
                                        "value": ""
                                    }
                                ],
                                "image": "mysql",
                                "imagePullPolicy": "Always",
                                "name": "member-mysql",
                                "ports": [
                                    {
                                        "containerPort": 3306,
                                        "protocol": "TCP"
                                    }
                                ],
                                "volumeMounts": [
                                    {
                                        "mountPath": "/var/lib/mysql/data",
                                        "name": "member-mysql-pvol"
                                    }
                                ]
                            }
                        ],
                        "volumes": [
                            {
                                "name": "member-mysql-pvol",
                                "persistentVolumeClaim": {
                                    "claimName": "member-mysql-claim"
                                }
                            }
                        ]
                    }
                },
                "triggers": [
                    {
                        "imageChangeParams": {
                            "automatic": true,
                            "containerNames": [
                                "member-mysql"
                            ],
                            "from": {
                                "kind": "ImageStreamTag",
                                "name": "mysql:latest",
                                "namespace": "openshift"
                            }
                        },
                        "type": "ImageChange"
                    }
                ]
            }
        },
        {
            "apiVersion": "v1",
            "kind": "PersistentVolumeClaim",
            "metadata": {
                "labels": {
                    "application": "member",
                    "template": "eap6-mysql-persistent-sti"
                },
                "name": "member-mysql-claim"
            },
            "spec": {
                "accessModes": [
                    "ReadWriteOnce"
                ],
                "resources": {
                    "requests": {
                        "storage": "512Mi"
                    }
                }
            }
        }
    ]
}

6. 发布应用
[student@workstation ~]$ oc create -f processedtemplate.json

也可以通过 oc new-app 命令 +  template  + 参数定义,直接创建应用
注意,参数 option 是 -p=, 而不是 -v 。
[student@workstation ~]$ oc new-app --template=eap6-mysql-persistent-sti \
-p=APPLICATION_NAME=member,\
APPLICATION_HOSTNAME=member.cloudapps0.example.com,\
GIT_URI=http://workstation.pod0.example.com/member,\
DB_JNDI=java:jboss/datasources/memberDS,\
DB_DATABASE=member,\
EAP_HTTPS_SECRET=eap-app-secret-member,\
EAP_HTTPS_KEYSTORE=keystore.jks,\
EAP_HTTPS_NAME=jboss,\
EAP_HTTPS_PASSWORD=mykeystorepass,\
DB_USERNAME=member,\
DB_PASSWORD=member

7. 访问应用
http://member.cloudapps0.example.com



8. Java 应用 pod 是如何访问 MySQL pod 的?
(1)查看了源代码,发现使用的是 JPA,只在 persistent.xml 中定义了 mysql datasource 的 JNDI 名字。
<persistence
    version="2.0"
    xmlns="http://java.sun.com/xml/ns/persistence"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://java.sun.com/xml/ns/persistence
        http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
    <persistence-unit name="primary">
        <!-- If you are running in a production environment, add a managed
         data source, this example data source is just for development and testing! -->
        <!-- The datasource is deployed as WEB-INF/hello-world-ds.xml, you
         can find it in the source at src/main/webapp/WEB-INF/hello-world-ds.xml -->
        <jta-data-source>java:jboss/datasources/hello-worldDS</jta-data-source>
        <properties>
            <!-- Properties for Hibernate -->
            <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
            <property name="hibernate.show_sql" value="false"/>
        </properties>
    </persistence-unit>
</persistence>
(2)进入应用 pod 后,进入 eap 6 安装目录,找到 /opt/eap/standalone/configuration/standalone-openshift.xml 文件,发现其中详细定义了 mysql datasource。

<datasources>
    <xa-datasource jndi-name="java:jboss/datasources/memberDS" pool-name="member_mysql" use-java-context="true" enabled="true">
        <xa-datasource-property name="ServerName">172.30.178.212</xa-datasource-property>
        <xa-datasource-property name="Port">3306</xa-datasource-property>
        <xa-datasource-property name="DatabaseName">member</xa-datasource-property>
        <driver>mysql</driver>
        <security>
            <user-name>member</user-name>
            <password>member</password>
        </security>
        <validation>
            <valid-connection-checker class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLValidConnectionChecker"></valid-connection-checker>
            <exception-sorter class-name="org.jboss.jca.adapters.jdbc.extensions.mysql.MySQLExceptionSorter"></exception-sorter>
        </validation>
    </xa-datasource>
    <datasource jta="false" jndi-name="java:jboss/datasources/memberDSObjectStore" pool-name="member_mysqlObjectStorePool" enabled="true">
        <connection-url>jdbc:mysql://172.30.178.212:3306/member</connection-url>
        <driver>mysql</driver>
        <security>
            <user-name>member</user-name>
            <password>member</password>
        </security>
    </datasource>
</datasources>

说明:172.30.178.212 是 member-mysql service 暴露的 IP 地址,3306 是 member-mysql service 暴露的端口,表明应用 pod 是通过 member-mysql service 去访问 member-mysql pod 的。