2012-12-05 41 views
22

Chúng tôi đang gặp sự cố khi kết nối với các ứng dụng Java đang chạy trong cụm EC2 của Amazon. Chúng tôi chắc chắn đã cho phép cả "cổng JMX" (thường là cổng đăng ký RMI) cổng máy chủ (hầu hết công việc) vào nhóm bảo mật cho các trường hợp được đề cập. Jconsole kết nối nhưng dường như treo và không bao giờ hiển thị bất kỳ thông tin nào.Cách kết nối với các cá thể Java chạy trên EC2 bằng cách sử dụng JMX

Chúng tôi đang chạy java của chúng tôi với một cái gì đó như sau:

java -server -jar foo.jar other parameters here > java.log 2>&1 

Chúng tôi đã cố gắng:

  • Telnets đến các cổng kết nối nhưng không có thông tin được hiển thị.
  • Chúng tôi có thể chạy jconsole trên bản thân bản thân bằng cách sử dụng từ xa X11 trên ssh và nó kết nối và hiển thị thông tin. Vì vậy, JRE xuất nội bộ.
  • Mở tất cả các cổng trong nhóm bảo mật. Weeee.
  • Sử dụng tcpdump để đảm bảo lưu lượng truy cập không đi đến các cổng khác.
  • Mô phỏng nó cục bộ. Chúng tôi luôn có thể kết nối với JRE địa phương của chúng tôi hoặc những người đang chạy ở nơi khác trên mạng của chúng tôi bằng cách sử dụng cùng các thông số ứng dụng.

java -version kết quả đầu ra:

OpenJDK Runtime Environment (IcedTea6 1.11.5) (amazon-53.1.11.5.47.amzn1-x86_64) 
OpenJDK 64-Bit Server VM (build 20.0-b12, mixed mode) 

Là một sang một bên, chúng ta đang sử dụng gói của tôi Simple JMX cho phép chúng ta thiết lập cả RMI registry và máy chủ cổng mà thường bán ngẫu nhiên được lựa chọn bởi các RMI đăng ký. Bạn cũng có thể ép buộc điều này với một cái gì đó giống như JMX URI sau đây:

service:jmx:rmi://localhost:" + serverPort + "/jndi/rmi://:" + registryPort + "/jmxrmi" 

Những ngày này chúng tôi sử dụng cùng một cổng cho cả máy chủ và đăng ký. Trong quá khứ, chúng tôi đã sử dụng X làm cổng đăng ký và X+1 cho cổng máy chủ để làm cho các quy tắc nhóm bảo mật trở nên dễ dàng. Bạn kết nối với cổng đăng ký trong jconsole hoặc bất kỳ ứng dụng khách JMX nào bạn đang sử dụng.

Trả lời

35

Chúng tôi đang gặp sự cố khi kết nối với các ứng dụng Java đang chạy trong cụm EC2 của Amazon.

Hóa ra vấn đề là sự kết hợp của hai cài đặt bị thiếu. Các lực lượng đầu tiên của JRE thích ipv4 và không phải là v6. Này là cần thiết (tôi đoán) vì chúng ta đang cố gắng để kết nối đến nó thông qua một địa chỉ v4:

-Djava.net.preferIPv4Stack=true 

Các chặn thực sự là một thực tế rằng JMX hoạt động bằng cách đầu tiên tiếp xúc với cổng RMI mà phản ứng với hostname và cổng cho máy khách JMX để kết nối. Không có cài đặt bổ sung, nó sẽ sử dụng IP cục bộ của hộp là địa chỉ ảo 10.X.X.X mà máy khách từ xa không thể định tuyến đến. Chúng tôi cần thêm cài đặt sau đây là bên ngoài tên máy chủ hoặc IP của máy chủ - trong trường hợp này, đó là tên máy chủ lưu trữ đàn hồi của máy chủ.

-Djava.rmi.server.hostname=ec2-107-X-X-X.compute-1.amazonaws.com 

Bí quyết, nếu bạn đang cố gắng tự động hóa các trường hợp EC2 của bạn (và tại sao bạn không làm), là cách tìm địa chỉ này trong thời gian chạy. Để làm điều đó bạn cần phải đặt một cái gì đó như sau trong script khởi động ứng dụng của chúng tôi:

# get our _external_ hostname 
RMI_HOST=`wget -q -O - http://169.254.169.254/latest/meta-data/public-hostname` 
... 
java -server \ 
    -Djava.net.preferIPv4Stack=true -Djava.rmi.server.hostname=$RMI_HOST \ 
    -jar foo.jar other parameters here > java.log 2>&1 

Các bí ẩn 169.254.169.254 IP trong lệnh wget trên đây cung cấp thông tin mà dụ EC2 có thể yêu cầu về chính nó. Tôi thất vọng rằng điều này không không bao gồm các thẻ chỉ khả dụng trong cuộc gọi được xác thực.

Ban đầu tôi đã sử dụng địa chỉ ipv4 bên ngoài nhưng có vẻ như JDK cố gắng tạo kết nối tới cổng máy chủ khi khởi động. Nếu nó sử dụng IP bên ngoài thì điều này đã làm chậm thời gian khởi động ứng dụng của chúng tôi cho đến khi hết thời gian chờ. Tên máy chủ công cộng phân giải cục bộ thành địa chỉ 10-bit và công khai ipv4 bên ngoài. Vì vậy, ứng dụng hiện đang bắt đầu nhanh và khách hàng JMX vẫn hoạt động. Woo hoo!

Hy vọng điều này sẽ giúp người khác. Chi phí cho tôi 3 giờ ngày hôm nay.

Để buộc máy chủ JMX bạn để bắt đầu máy chủ RMI registry trên các cổng được chỉ định, do đó bạn có thể chặn chúng trong các nhóm EC2 an, thấy câu trả lời này:

How to close rmiregistry running on particular port?

Chỉnh sửa:

Chúng tôi vừa gặp sự cố này. Có vẻ như mã Java JMX đang thực hiện một số tra cứu tên máy chủ trên tên máy chủ của hộp và sử dụng chúng để thử kết nối và xác minh kết nối JMX.

Sự cố có vẻ là yêu cầu rằng tên máy chủ cục bộ của hộp phải giải quyết thành địa phương-ip của hộp. Ví dụ: nếu /etc/sysconfig/network của bạn có HOSTNAME=server1.foobar.com thì nếu bạn thực hiện tra cứu DNS trên server1.foobar.com, bạn sẽ nhận được địa chỉ ảo 10-NET. Chúng tôi đã tạo tệp /etc/hosts của riêng mình và tên máy chủ lưu trữ cục bộ bị thiếu trong tệp. Điều này khiến ứng dụng của chúng tôi tạm dừng khi khởi động hoặc không khởi động được.

Cuối cùng

Một cách để đơn giản hóa việc tạo ra JMX bạn là sử dụng SimpleJMX package tôi.

+2

Bạn có thể phát hành cuộc gọi DescribeInstances để xác định thẻ nào áp dụng cho trường hợp của bạn nếu bạn thực sự cần (ví dụ: thông qua các tiện ích dòng lệnh EC2), nhưng thực hành tốt hơn là truyền thông tin cấu hình cho một cá thể thông qua dữ liệu người dùng. – willglynn

+0

Cảm ơn @willglynn. Tôi đã hy vọng nhận được các thẻ _without_ phải thêm các khóa truy cập/bí mật của tôi vào cá thể của tôi. Vâng, bây giờ chúng tôi sử dụng UserData nhưng tôi muốn nó là loại khóa 'key = value' để các ops không mắc lỗi đánh máy. – Gray

+2

Có một cơ chế để tự động tạo và phân phối thông tin đăng nhập AWS trên cùng một kênh siêu dữ liệu mẫu: xem [Vai trò IAM cho các trường hợp EC2] (http://aws.typepad.com/aws/2012/06/iam-roles-for-ec2 -instances-simplified-secure-access-to-aws-service-apis-from-ec2.html). Bạn có thể tạo một vai trò hạn chế truy cập vào EC2 DescribeInstances, cho phép bạn tự động hóa mọi thứ mà không cần phải phát điên từ việc quản lý thông tin đăng nhập. – willglynn

1

Câu trả lời được đưa ra bởi Gray làm việc cho tôi, tuy nhiên tôi thấy rằng tôi phải mở cổng TCP 0 đến 65535 hoặc tôi không nhận được. Tôi nghĩ rằng mà bạn có thể kết nối trên cổng JMX chính, sau đó lấy một cái khác được chỉ định. Tôi nhận được điều đó từ this blog post luôn hoạt động tốt cho tôi.

+0

Chúng tôi làm _not_ phải làm điều đó @Eric. Chúng tôi chỉ có cổng RMI và cổng máy chủ JMX được mở. Bạn cần phải chỉ định cả hai cổng khi bạn tạo máy chủ JMX của mình. Là một gói đơn giản, sang một bên, gói simpleJmx thực hiện điều đó khá dễ dàng cho bạn: http://256.com/sources/simplejmx/ – Gray

+0

Xem câu trả lời này: http://stackoverflow.com/questions/8386001/how-to-close-rmiregistry- running-on-specific-port/8386052 # 8386052 – Gray

+0

Màu xám, điều đó thật thú vị ... Tuy nhiên, tôi đang sử dụng thư viện Coda Hale Metrics, nó có phép thuật riêng trong việc thiết lập JMX .... Tôi tự hỏi liệu nó có thể cho tôi làm những gì simplejmx làm gì? –

11

Mỗi câu trả lời thứ hai Why does JMX connection to Amazon EC2 fail?, khó khăn ở đây là theo mặc định cổng RMI được chọn ngẫu nhiên và khách hàng cần quyền truy cập vào cả hai cổng JMX và RMI. Nếu bạn đang chạy jdk7u4 hoặc mới hơn, cổng RMI có thể được chỉ định thông qua thuộc tính ứng dụng.Bắt đầu từ máy chủ của tôi với các thiết lập JMX sau làm việc cho tôi:

Nếu không có xác thực:

-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=9999 
-Dcom.sun.management.jmxremote.rmi.port=9998 
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=false 
-Djava.rmi.server.hostname=<public EC2 hostname> 

Với xác thực:

-Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port=9999 
-Dcom.sun.management.jmxremote.rmi.port=9998 
-Dcom.sun.management.jmxremote.ssl=false 
-Dcom.sun.management.jmxremote.authenticate=true 
-Dcom.sun.management.jmxremote.password.file=/path/to/jmxremote.password 
-Djava.rmi.server.hostname=<public EC2 hostname> 

Tôi cũng mở cổng 9998-9999 trong nhóm bảo mật EC2 cho tôi ví dụ.

+0

Nếu cá thể của bạn không có tên máy chủ EC2 công cộng (ẩn nó sau ELB chẳng hạn) và bạn chỉ muốn jmx làm việc nội bộ, sau đó thiết lập các cổng jmx và nhóm bảo mật như Mark mô tả ở trên và đặt tên máy chủ trong cho java.rmi.server.hostname. Bạn sẽ biết trường hợp của bạn được thiết lập theo cách này nếu bạn gọi/meta-data/public-hostname/endpoint được liệt kê trong câu trả lời của @ Gray và bạn nhận được một phản hồi rỗng. – Matt

1

Một chút cách tiếp cận khác nhau bằng cách sử dụng đường hầm ssh

  1. Vượt qua những lá cờ sau để JVM

-Dcom.sun.management.jmxremote.port=1099 -Djava.net.preferIPv4Stack=true -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false -Djava.rmi.server.hostname=127.0.0.1

  1. Kiểm tra các cổng java bắt đầu để sử dụng

netstat -tulpn | grep java

tcp 0 0 0.0.0.0:37484 0.0.0.0:* LISTEN 2904/java tcp 0 0 0.0.0.0:1099 0.0.0.0:* LISTEN 2904/java tcp 0 0 0.0.0.0:45828 0.0.0.0:* LISTEN 2904/java

    hầm ssh
  1. Make cho tất cả các cổng

ssh -N -L 1099:127.0.0.1:1099 [email protected]<ec2_ip> ssh -N -L 37484:127.0.0.1:37484 [email protected]<ec2_ip> ssh -N -L 45828:127.0.0.1:45828 [email protected]<ec2_ip>

  1. Connect bởi Java Sứ mệnh Kiểm soát "localhost: 1099"
Các vấn đề liên quan